26.6. timeit —小さなコードスニペットの実行時間を測定する—Pythonドキュメント
26.6。 timeit —小さなコードスニペットの実行時間を測定する
バージョン2.3の新機能。
ソースコード: :source: `Lib / timeit.py`
このモジュールは、Pythonコードの小さなビットの時間を計る簡単な方法を提供します。 コマンドラインインターフェイスと呼び出し可能の両方があります。 実行時間を測定するための多くの一般的なトラップを回避します。 O'Reillyが発行した Python Cookbook の「Algorithms」の章へのTimPetersの紹介も参照してください。
26.6.1。 基本的な例
次の例は、コマンドラインインターフェイスを使用して3つの異なる式を比較する方法を示しています。
$ python -m timeit '"-".join(str(n) for n in range(100))'
10000 loops, best of 3: 40.3 usec per loop
$ python -m timeit '"-".join([str(n) for n in range(100)])'
10000 loops, best of 3: 33.4 usec per loop
$ python -m timeit '"-".join(map(str, range(100)))'
10000 loops, best of 3: 25.2 usec per loop
これは、 Pythonインターフェイスから次の方法で実現できます。
>>> import timeit
>>> timeit.timeit('"-".join(str(n) for n in range(100))', number=10000)
0.8187260627746582
>>> timeit.timeit('"-".join([str(n) for n in range(100)])', number=10000)
0.7288308143615723
>>> timeit.timeit('"-".join(map(str, range(100)))', number=10000)
0.5858950614929199
ただし、 timeit は、コマンドラインインターフェイスが使用されている場合にのみ繰り返し回数を自動的に決定することに注意してください。 例セクションには、より高度な例があります。
26.6.2。 Pythonインターフェース
このモジュールは、3つの便利な関数とパブリッククラスを定義します。
- timeit.timeit(stmt='pass', setup='pass', timer=<default timer>, number=1000000)
指定されたステートメント、 setup コード、および timer 関数を使用して Timer インスタンスを作成し、 numberを使用して timeit()メソッドを実行します。 実行。
バージョン2.6の新機能。
- timeit.repeat(stmt='pass', setup='pass', timer=<default timer>, repeat=3, number=1000000)
指定されたステートメント、 setup コード、および timer 関数を使用して Timer インスタンスを作成し、指定された[X159X ] repeat countおよび number 実行。
バージョン2.6の新機能。
- timeit.default_timer()
- プラットフォーム固有の方法で、デフォルトのタイマーを定義します。 Windowsでは、 time.clock()の粒度はマイクロ秒ですが、 time.time()の粒度は1/60秒です。 Unixでは、 time.clock()の粒度は1/100秒であり、 time.time()の方がはるかに正確です。 どちらのプラットフォームでも、 default_timer()は、CPU時間ではなく、実時間です。 これは、同じコンピューターで実行されている他のプロセスがタイミングを妨げる可能性があることを意味します。
- class timeit.Timer(stmt='pass', setup='pass', timer=<timer function>)
小さなコードスニペットの実行速度のタイミングに関するクラス。
コンストラクターは、タイミングをとるステートメント、セットアップに使用される追加のステートメント、およびタイマー関数を受け取ります。 どちらのステートメントもデフォルトで
'pass'
になります。 タイマー機能はプラットフォームに依存します(モジュールのドキュメント文字列を参照)。 stmt および setup には、複数行の文字列リテラルが含まれていない限り、;
または改行で区切られた複数のステートメントを含めることもできます。最初のステートメントの実行時間を測定するには、 timeit()メソッドを使用します。 repeat()メソッドは、 timeit()を複数回呼び出して、結果のリストを返すのに便利です。
バージョン2.6で変更: stmt および setup パラメーターは、引数なしで呼び出し可能なオブジェクトも取得できるようになりました。 これにより、それらへの呼び出しがタイマー関数に埋め込まれ、 timeit()によって実行されます。 この場合、余分な関数呼び出しがあるため、タイミングのオーバーヘッドが少し大きくなることに注意してください。
- timeit(number=1000000)
メインステートメントの number 実行時間。 これにより、セットアップステートメントが1回実行され、メインステートメントの実行にかかる時間がfloatとして秒単位で測定されて返されます。 引数はループを通過する回数であり、デフォルトは100万回です。 使用するmainステートメント、setupステートメント、timer関数がコンストラクターに渡されます。
ノート
デフォルトでは、 timeit()は、タイミング中にガベージコレクションを一時的にオフにします。 このアプローチの利点は、独立したタイミングをより比較できるようにすることです。 この欠点は、GCが測定される機能のパフォーマンスの重要な要素である可能性があることです。 その場合、 setup 文字列の最初のステートメントとしてGCを再度有効にすることができます。 例えば:
timeit.Timer('for i in xrange(10): oct(i)', 'gc.enable()').timeit()
- repeat(repeat=3, number=1000000)
timeit()を数回呼び出します。
これは、 timeit()を繰り返し呼び出して、結果のリストを返す便利な関数です。 最初の引数は、 timeit()を呼び出す回数を指定します。 2番目の引数は、 timeit()の number 引数を指定します。
ノート
結果ベクトルから平均と標準偏差を計算し、これらを報告するのは魅力的です。 ただし、これはあまり役に立ちません。 通常、最小値は、マシンが特定のコードスニペットを実行できる速度の下限を示します。 結果ベクトルの値が高いのは、通常、Pythonの速度の変動ではなく、タイミングの精度を妨げる他のプロセスが原因です。 したがって、結果の min()は、おそらく関心があるはずの唯一の数値です。 その後、ベクトル全体を見て、統計ではなく常識を適用する必要があります。
- print_exc(file=None)
時限コードからトレースバックを出力するヘルパー。
典型的な使用法:
t = Timer(...) # outside the try/except try: t.timeit(...) # or t.repeat(...) except: t.print_exc()
標準のトレースバックに対する利点は、コンパイルされたテンプレートのソース行が表示されることです。 オプションの file 引数は、トレースバックの送信先を指示します。 デフォルトは sys.stderr です。
26.6.3。 コマンドラインインターフェイス
コマンドラインからプログラムとして呼び出される場合、次の形式が使用されます。
python -m timeit [-n N] [-r N] [-s S] [-t] [-c] [-h] [statement ...]
次のオプションが理解されている場合:
- -n N, --number=N
- 'ステートメント'を実行する回数
- -r N, --repeat=N
- タイマーを繰り返す回数(デフォルトは3)
- -s S, --setup=S
- 最初に1回実行されるステートメント(デフォルト
pass
)
- -t, --time
- time.time()を使用します(Windowsを除くすべてのプラットフォームでデフォルト)
- -c, --clock
- time.clock()を使用します(Windowsのデフォルト)
- -v, --verbose
- 生のタイミング結果を出力します。 より多くの桁の精度のために繰り返す
- -h, --help
- 短い使用法メッセージを印刷して終了します
複数行のステートメントは、各行を個別のステートメント引数として指定することで指定できます。 インデントされた行は、引数を引用符で囲み、先頭にスペースを使用することで可能です。 複数の -s オプションは同様に扱われます。
-n が指定されていない場合、合計時間が少なくとも0.2秒になるまで、10の累乗を連続して試行することにより、適切なループ数が計算されます。
default_timer()測定は、同じマシンで実行されている他のプログラムの影響を受ける可能性があるため、正確なタイミングが必要な場合は、タイミングを数回繰り返し、最適な時間を使用することをお勧めします。 -r オプションはこれに適しています。 ほとんどの場合、デフォルトの3回の繰り返しで十分です。 Unixでは、 time.clock()を使用してCPU時間を測定できます。
ノート
passステートメントの実行に関連する特定のベースラインオーバーヘッドがあります。 ここのコードはそれを隠そうとはしていませんが、あなたはそれを知っているべきです。 ベースラインオーバーヘッドは、引数なしでプログラムを呼び出すことで測定でき、Pythonのバージョン間で異なる場合があります。 また、古いPythonバージョンをPython 2.3と公平に比較するには、SET_LINENO
命令のタイミングを回避するために、古いバージョンに対してPythonの-O
オプション(最適化を参照)を使用することをお勧めします。
26.6.4。 例
最初に一度だけ実行されるセットアップステートメントを提供することが可能です。
$ python -m timeit -s 'text = "sample string"; char = "g"' 'char in text'
10000000 loops, best of 3: 0.0877 usec per loop
$ python -m timeit -s 'text = "sample string"; char = "g"' 'text.find(char)'
1000000 loops, best of 3: 0.342 usec per loop
>>> import timeit
>>> timeit.timeit('char in text', setup='text = "sample string"; char = "g"')
0.41440500499993504
>>> timeit.timeit('text.find(char)', setup='text = "sample string"; char = "g"')
1.7246671520006203
Timer クラスとそのメソッドを使用して同じことを行うことができます。
>>> import timeit
>>> t = timeit.Timer('char in text', setup='text = "sample string"; char = "g"')
>>> t.timeit()
0.3955516149999312
>>> t.repeat()
[0.40193588800002544, 0.3960157959998014, 0.39594301399984033]
次の例は、複数の行を含む式の時間を計る方法を示しています。 ここでは、 hasattr()との使用コストを比較します。 try / exception を使用して、オブジェクト属性の欠落と存在をテストします。
$ python -m timeit 'try:' ' str.__nonzero__' 'except AttributeError:' ' pass'
100000 loops, best of 3: 15.7 usec per loop
$ python -m timeit 'if hasattr(str, "__nonzero__"): pass'
100000 loops, best of 3: 4.26 usec per loop
$ python -m timeit 'try:' ' int.__nonzero__' 'except AttributeError:' ' pass'
1000000 loops, best of 3: 1.43 usec per loop
$ python -m timeit 'if hasattr(int, "__nonzero__"): pass'
100000 loops, best of 3: 2.23 usec per loop
>>> import timeit
>>> # attribute is missing
>>> s = """\
... try:
... str.__nonzero__
... except AttributeError:
... pass
... """
>>> timeit.timeit(stmt=s, number=100000)
0.9138244460009446
>>> s = "if hasattr(str, '__bool__'): pass"
>>> timeit.timeit(stmt=s, number=100000)
0.5829014980008651
>>>
>>> # attribute is present
>>> s = """\
... try:
... int.__nonzero__
... except AttributeError:
... pass
... """
>>> timeit.timeit(stmt=s, number=100000)
0.04215312199994514
>>> s = "if hasattr(int, '__bool__'): pass"
>>> timeit.timeit(stmt=s, number=100000)
0.08588060699912603
timeit モジュールに定義した関数へのアクセスを許可するには、インポートステートメントを含む setup パラメーターを渡すことができます。
def test():
"""Stupid test function"""
L = []
for i in range(100):
L.append(i)
if __name__ == '__main__':
import timeit
print(timeit.timeit("test()", setup="from __main__ import test"))