2017-04-03 4 views
0

デコレータがfunctools.lru_cache()である再帰関数があります。空のキャッシュから複数回実行したいこれを行う1つの方法は、毎回キャッシュをクリアすることですが、これにはキャッシュクリア時間が含まれます。Python timeit.timeit文の間にアンタイムドアクションを行う

これは私が現在持っているものです。

@functools.lru_cache(maxsize=None) 
def recursive_function(n): 
    # ... 
    return sum(recursive_function(n - i) * b for i, b in enumerate(other_list)) 

def time(number, n): 
    return timeit.timeit(
     'f({}); f.cache_clear()'.format(n), 
     'from {} import recursive_function as f'.format(__name__), 
     number=number 
    ) 

キャッシュが指数関数的に時間を短縮し、それはそれを呼び出して、一度呼び出された後は、再び取るように私はまだ、キャッシュでそれを時間を計るたいです〜0ms、キャッシュされた値を取得するだけです。

timeit.timeitの文の間に何かする方法はありませんか?または、cache_clearの前にタイマーを一時停止する?

+0

私の間違い、間違ったことを読む – Alex

答えて

1

あなたが持つ関数のnumberコピー、それぞれを作り出すことができる彼らの独立しlru_cacheラッパー:

setup = '''\ 
    from {name} import recursive_function as f 
    f = iter([ 
     functools.lru_cache(maxsize=None)(recursive_function.__wrapped__) 
     for _ in range({number})]) 
    n = {n} 
    next_ = next 
'''.format(name=__name__, number=number, n=n) 
test = '''\ 
    recursive_function = next_(f) 
    recursive_funcion.__globals__['recursive_funcion'] = recursive_funcion 
    recursive_function(n) 
''' 
return timeit.timeit(test, setup, number=number) 

セットアップ、number個別に装飾された機能は、個別のLRUキャッシュとフロントアップ、それぞれをオブジェクト作成し、このためのイテレータを作成します。次に、テストではnext()関数を使用して次の使用可能な関数オブジェクトを取得し、それをテストに使用します。

doは、現在のグローバル名recursive_functionを毎回置き換える必要があります。そうしないと、再帰呼び出しは新しい装飾バージョンを検出しません。これは若干の欠点ですが、タイムトライアルを実行せず、その後キャッシュが空であることを期待しないでください(代わりに最後のテストの結果が含まれます)。

ので、これは動作します:オリジナルの非キャッシュされた機能はデコレータ構文は新しい関数オブジェクトを生成するデコレータオブジェクトへの呼び出しのためだけ糖衣構文である

  • recursive_function.__wrapped__としてまだ利用できる

    これは(グローバル名前検索ペナルティを避けるために、ローカルにバインドされているだけnext()呼び出し、)最小限のオーバーヘッドで、個々のテストクリーンなキャッシュを、与えます。

    +0

    @Artyer:関数自体の中で参照される名前 'recursive_function'が元のグローバルで検索されるので、再帰呼び出しは間違った関数オブジェクトを見つけます。 –

    関連する問題