Python で記述された Web アプリケーションの一般的な読み込み時間を最適化しようとしています。私のアプリケーションは多くのモジュールを使用していますが、その中には、特定のリクエストに実際に必要な場合とそうでない場合があります。
ページの読み込み時間は、エンドユーザーがサイトの品質を認識する重要な要素であるため、不要なモジュールの読み込みの影響を軽減しようとしています。特に、グローバルを初期化するのに必要な時間 (およびメモリ) を削減しようとしています。まったく必要ありません。
簡単に言えば、私の目標は次のとおりです。
- モジュールの初期化時間を可能な限り短縮します (CPU 使用率ではありません)。
- 不要なグローバル変数によって消費されるメモリを減らすため。
説明のために、簡単なモジュールの例を次に示します。
COMMON = set(('alice', 'has', 'cat', 'with', 'blue', 'eyes'))
セットの構築には時間がかかります。使用しないCOMMON
場合COMMON
、ロード時間とメモリの無駄になります。
明らかに、単一のモジュール/グローバルの場合、コストは無視できますが、100 個の変数を持つ 100 個のモジュールがある場合はどうなるでしょうか?
これを高速化する 1 つの方法は、次のように初期化を遅らせることです。
__cache_common = None
def getCommon():
global __cache_common
# not use before
if __cache_common is None:
__cache_common = set(('alice', 'has', 'cat', 'with', 'blue', 'eyes'))
# get cached value
return __cache_common
ロード時間とメモリを節約し、CPU をいくらか犠牲にします。
他にもいくつかの手法を試しました (以下を参照)。そのうちの 2 つは、上記の単純なキャッシュよりも少し高速です。
特定のリクエストで使用されない可能性のあるモジュールとグローバルのロード時間をさらに短縮するために使用できる別の手法はありますか?
これまでに試したアプローチには、Python 2.6 以降が必要です。
from timeit import Timer
__repeat = 1000000
__cache = None
def getCache():
return __cache
def getCacheTest():
for i in range(__repeat):
getCache()
def getLocal():
return set(('alice', 'has', 'cat', 'with', 'blue', 'eyes'))
def getLocalTest():
for i in range(__repeat):
getLocal()
def getLazyIf():
global __cache
if __cache is None:
__cache = getLocal()
return __cache
def getLazyIfTest():
for i in range(__repeat):
getLazyIf()
def __realLazy():
return __cache
def getLazyDynamic():
global __cache, getLazyDynamic
__cache = getLocal()
getLazyDynamic = __realLazy
return __cache
def getLazyDynamicTest():
for i in range(__repeat):
getLazyDynamic()
def getLazyDynamic2():
global __cache, getLazyDynamic2
__cache = getLocal()
def __realLazy2():
return __cache
getLazyDynamic2 = __realLazy2
return __cache
def getLazyDynamic2Test():
for i in range(__repeat):
getLazyDynamic2()
print sum(Timer(getCacheTest).repeat(3, 1)), getCacheTest, 'raw access'
print sum(Timer(getLocalTest).repeat(3, 1)), getLocalTest, 'repeat'
print sum(Timer(getLazyIfTest).repeat(3, 1)), getLazyIfTest, 'conditional'
print sum(Timer(getLazyDynamicTest).repeat(3, 1)), getLazyDynamicTest, 'hook'
print sum(Timer(getLazyDynamic2Test).repeat(3, 1)), getLazyDynamic2Test, 'scope hook'
Python 2.7 では、次のタイミングが得られます (最適なのはスコープなしのフックです)。
1.01902420559 <function getCacheTest at 0x012AE170> raw access
5.40701374057 <function getLocalTest at 0x012AE1F0> repeat
1.39493902158 <function getLazyIfTest at 0x012AE270> conditional
1.06692051643 <function getLazyDynamicTest at 0x012AE330> hook
1.15909591862 <function getLazyDynamic2Test at 0x012AE3B0> scope hook