423

何をするのかという概念は理解してtimeitいますが、コードに実装する方法がわかりません。

insertion_sort2つの関数sayとtim_sort、をと比較するにはどうすればよいtimeitですか?

4

14 に答える 14

318

インタラクティブな Python セッションで使用する場合timeitは、次の 2 つの便利なオプションがあります。

  1. IPythonシェルを使用します。便利%timeitな特殊機能を備えています。

    In [1]: def f(x):
       ...:     return x*x
       ...: 
    
    In [2]: %timeit for x in range(100): f(x)
    100000 loops, best of 3: 20.3 us per loop
    
  2. __main__標準の Python インタープリターでは、setup ステートメントからインポートすることで、インタラクティブ セッション中に以前に定義した関数やその他の名前にアクセスできます。

    >>> def f(x):
    ...     return x * x 
    ... 
    >>> import timeit
    >>> timeit.repeat("for x in range(100): f(x)", "from __main__ import f",
                      number=100000)
    [2.0640320777893066, 2.0876040458679199, 2.0520210266113281]
    
于 2011-11-22T01:41:48.890 に答える
308

timeitが機能する方法は、セットアップコードを一度実行してから、一連のステートメントを繰り返し呼び出すことです。したがって、並べ替えをテストする場合は、インプレース並べ替えの1つのパスが、既に並べ替えられたデータの次のパスに影響を与えないように注意する必要があります(もちろん、Timsortは最高のパフォーマンスを発揮するため、非常に優れています。データがすでに部分的に順序付けられている場合)。

並べ替えのテストを設定する方法の例を次に示します。

>>> import timeit

>>> setup = '''
import random

random.seed('slartibartfast')
s = [random.random() for i in range(1000)]
timsort = list.sort
'''

>>> print min(timeit.Timer('a=s[:]; timsort(a)', setup=setup).repeat(7, 1000))
0.334147930145

一連のステートメントは、パスごとにソートされていないデータの新しいコピーを作成することに注意してください。

また、測定スイートを7回実行し、最適な時間を維持するタイミング手法にも注意してください。これにより、システムで実行されている他のプロセスによる測定の歪みを減らすことができます。

これらは、timeitを正しく使用するための私のヒントです。お役に立てれば :-)

于 2011-11-22T01:38:10.127 に答える
162

秘密を教えましょうtimeit。コマンド ラインで使用するのが一番です。

コマンド ラインでtimeitは、適切な統計分析を行います。最短の実行にかかった時間を示します。タイミングのすべての誤差が正であるため、これは良いことです。したがって、最短時間には誤差が最も少なくなります。コンピューターが計算できる以上の速度で計算することはできないため、負のエラーを取得する方法はありません。

したがって、コマンドライン インターフェイスは次のようになります。

%~> python -m timeit "1 + 2"
10000000 loops, best of 3: 0.0468 usec per loop

それはとても簡単ですよね?

あなたはものを設定することができます:

%~> python -m timeit -s "x = range(10000)" "sum(x)"
1000 loops, best of 3: 543 usec per loop

これも便利です!

複数の行が必要な場合は、シェルの自動継続を使用するか、別の引数を使用できます。

%~> python -m timeit -s "x = range(10000)" -s "y = range(100)" "sum(x)" "min(y)"
1000 loops, best of 3: 554 usec per loop

それはのセットアップを与える

x = range(1000)
y = range(100)

と時代

sum(x)
min(y)

timeitより長いスクリプトが必要な場合は、Python スクリプト内に移動したくなるかもしれません。コマンドラインの方が分析とタイミングが単純に優れているため、これは避けることをお勧めします。代わりに、シェル スクリプトを作成する傾向があります。

 SETUP="

 ... # lots of stuff

 "

 echo Minmod arr1
 python -m timeit -s "$SETUP" "Minmod(arr1)"

 echo pure_minmod arr1
 python -m timeit -s "$SETUP" "pure_minmod(arr1)"

 echo better_minmod arr1
 python -m timeit -s "$SETUP" "better_minmod(arr1)"

 ... etc

複数の初期化が原因で、これには少し時間がかかる場合がありますが、通常は大したことではありません。


しかし、モジュール内で使用したい場合はどうでしょうか?timeit

簡単な方法は次のとおりです。

def function(...):
    ...

timeit.Timer(function).timeit(number=NUMBER)

これにより、その回数を実行するための累積的な (最小ではありません!) 時間が得られます。

適切な分析.repeatを行うには、最小限のものを使用して取得します。

min(timeit.Timer(function).repeat(repeat=REPEATS, number=NUMBER))

通常、オーバーヘッドを下げるfunctools.partial代わりに、これを と組み合わせる必要があります。lambda: ...したがって、次のようなものがあります。

from functools import partial

def to_time(items):
    ...

test_items = [1, 2, 3] * 100
times = timeit.Timer(partial(to_time, test_items)).repeat(3, 1000)

# Divide by the number of repeats
time_taken = min(times) / 1000

次のこともできます。

timeit.timeit("...", setup="from __main__ import ...", number=NUMBER)

これにより、コマンドラインからのインターフェイスに近いものが得られますが、それほどクールではありません。"from __main__ import ..."によって作成された人工的な環境内で、メイン モジュールのコードを使用できますtimeit

これは の便利なラッパーでTimer(...).timeit(...)あり、タイミングが特に得意ではないことに注意してください。私は個人的に、上で示したように使用することをはるかに好みTimer(...).repeat(...)ます。


警告

timeitどこでも保持することにはいくつかの注意事項があります。

  • オーバーヘッドは考慮されていません。x += 1加算にかかる時間を調べるために time を使いたいとしましょう:

    >>> python -m timeit -s "x = 0" "x += 1"
    10000000 loops, best of 3: 0.0476 usec per loop
    

    ええと、0.0476 µsではありません。あなたはそれがそれ以下であることを知っているだけです。すべてのエラーは正です。

    したがって、純粋なオーバーヘッドを見つけてみてください。

    >>> python -m timeit -s "x = 0" ""      
    100000000 loops, best of 3: 0.014 usec per loop
    

    これは、タイミングだけで30%の優れたオーバーヘッドです! これにより、相対的なタイミングが大幅に歪む可能性があります。しかし、追加のタイミングだけが本当に気になりました。の検索タイミングxもオーバーヘッドに含める必要があります。

    >>> python -m timeit -s "x = 0" "x"
    100000000 loops, best of 3: 0.0166 usec per loop
    

    違いはそれほど大きくありませんが、そこにあります。

  • 変異方法は危険です。

    >>> python -m timeit -s "x = [0]*100000" "while x: x.pop()"
    10000000 loops, best of 3: 0.0436 usec per loop
    

    しかし、それは完全に間違っています! x最初の反復後の空のリストです。再初期化する必要があります:

    >>> python -m timeit "x = [0]*100000" "while x: x.pop()"
    100 loops, best of 3: 9.79 msec per loop
    

    しかし、多くのオーバーヘッドがあります。その分は別途計上。

    >>> python -m timeit "x = [0]*100000"                   
    1000 loops, best of 3: 261 usec per loop
    

    ここでオーバーヘッドを差し引くのは妥当であることに注意してください。これは、オーバーヘッドが時間のごく一部であるためです。

    あなたの例では、挿入ソートとティムソートの両方が、すでにソートされたリストに対して完全に異常なタイミング動作をしていることに注意してください。random.shuffleこれは、タイミングを台無しにしたくない場合は、並べ替えの間に必要になることを意味します。

于 2014-06-08T11:51:43.610 に答える
118

コード/関数の 2 つのブロックをすばやく比較したい場合は、次のようにします。

import timeit

start_time = timeit.default_timer()
func1()
print(timeit.default_timer() - start_time)

start_time = timeit.default_timer()
func2()
print(timeit.default_timer() - start_time)
于 2015-04-08T10:33:05.513 に答える
48

timeit を使用する最も簡単な方法は、コマンドラインからです。

与えられた test.py :

def InsertionSort(): ...
def TimSort(): ...

次のように実行します。

% python -mtimeit -s'import test' 'test.InsertionSort()'
% python -mtimeit -s'import test' 'test.TimSort()'
于 2011-11-22T01:28:22.947 に答える
27

私にとって、これが最速の方法です:

import timeit
def foo():
    print("here is my code to time...")


timeit.timeit(stmt=foo, number=1234567)
于 2018-01-17T13:49:51.240 に答える
4

以下のそれぞれで同じ辞書をセットアップし、実行時間をテストしてみましょう。

setup引数は基本的に辞書を設定しています

Number は、コードを 1000000 回実行することです。セットアップではなくstmt

これを実行すると、index が get よりもはるかに高速であることがわかります。何度も実行して確認できます。

このコードは基本的に、辞書で c の値を取得しようとします。

import timeit

print('Getting value of C by index:', timeit.timeit(stmt="mydict['c']", setup="mydict={'a':5, 'b':6, 'c':7}", number=1000000))
print('Getting value of C by get:', timeit.timeit(stmt="mydict.get('c')", setup="mydict={'a':5, 'b':6, 'c':7}", number=1000000))

これが私の結果です。あなたの結果は異なります。

インデックス別: 0.20900007452246427

取得: 0.54841166886888

于 2016-09-26T15:31:21.647 に答える