-1

Python で記述された Web アプリケーションの一般的な読み込み時間を最適化しようとしています。私のアプリケーションは多くのモジュールを使用していますが、その中には、特定のリクエストに実際に必要な場合とそうでない場合があります。

ページの読み込み時間は、エンドユーザーがサイトの品質を認識する重要な要素であるため、不要なモジュールの読み込みの影響を軽減しようとしています。特に、グローバルを初期化するのに必要な時間 (およびメモリ) を削減しようとしています。まったく必要ありません。

簡単に言えば、私の目標は次のとおりです。

  1. モジュールの初期化時間を可能な限り短縮します (CPU 使用率ではありません)。
  2. 不要なグローバル変数によって消費されるメモリを減らすため

説明のために、簡単なモジュールの例を次に示します。

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
4

1 に答える 1

1

import ステートメントはモジュールを実行するため、そのセマンティクスを変更する必要はありません。

それらを必要とする関数またはメソッド内に import ステートメントを押し込んでみませんか? そうすれば、アプリケーションの起動時ではなく、必要なときにのみ発生します。

グローバルについても同様です-それらをクラス静的または何かに変えます。とにかく、多くのグローバルを持つことは悪いスタイルです。

しかし、なぜこれが問題なのですか?本当に多くのモジュールを含めて、単にそれらを見つけるだけで処理が遅くなるのですか? それとも、含まれているパッケージの一部が多くのコストのかかる初期化 (接続を開くなど) を行っているのですか? 私のお金は2番目です。スローダウンの原因となるモジュールを作成した場合は、初期化を適切なコンストラクターにラップすることを検討してください。

于 2012-03-05T17:31:11.350 に答える