回答:
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を正しく使用するための私のヒントです。お役に立てれば :-)
.repeat(7,1000)
すでに(同じシードを使用して)これを行っているということです!したがって、あなたのソリューションは完璧なIMOです。
.repeat(7, 1000)
対.repeat(2, 3500)
Vsが.repeat(35, 200
)によるシステム負荷にエラーが原因の入力変動にエラーと比較する方法に依存しなければなりません。お使いのシステムに大きな負荷がかかっ常にあり、あなたは(あなたが稀アイドル状態でそれをキャッチしたときに)実行時間分布の左側に細長い尾を見れば、極端なケースでは、あなたも見つけるかもしれない.repeat(7000,1)
よりも有用であることが.repeat(7,1000)
、あなたの場合7000ランを超える予算を組むことはできません。
timeit
インタラクティブなPythonセッションで使用する場合、2つの便利なオプションがあります。
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
標準のPythonインタープリターで__main__
は、セットアップセッションでインポートすることにより、インタラクティブセッション中に以前に定義した関数やその他の名前にアクセスできます。
>>> 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]
from __main__ import f
技術を示すための+1 。これは、広く知られているとは思いません。これは、関数やメソッドの呼び出しがタイミングをとられているこのような場合に役立ちます。その他の場合(一連のステップのタイミングをとる)、関数呼び出しのオーバーヘッドが発生するため、あまり役に立ちません。
%timeit f(x)
sys._getframe(N).f_globals
)が最初からデフォルトになっているはずです。
私は秘密を打ち明けましょう:使用する最良の方法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
追加にかかる時間を調べるために、時間をかけたいとしましょう。
>>> 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
、タイミングの破壊を回避したい場合は、ソートの間にソートが必要になることを意味します。
timeit
実行しpass
ます。もちろん、これには時間がかかります。任意の引数を指定している場合は、pass
なりません実行されますので、いくつかの減算0.014
タイミング毎からUSECSすることは正しくないだろう。
# Генерация целых чисел
def gen_prime(x):
multiples = []
results = []
for i in range(2, x+1):
if i not in multiples:
results.append(i)
for j in range(i*i, x+1, i):
multiples.append(j)
return results
import timeit
# Засекаем время
start_time = timeit.default_timer()
gen_prime(3000)
print(timeit.default_timer() - start_time)
# start_time = timeit.default_timer()
# gen_prime(1001)
# print(timeit.default_timer() - start_time)
これはうまくいきます:
python -m timeit -c "$(cat file_name.py)"
次のそれぞれに同じ辞書を設定し、実行時間をテストします。
セットアップ引数は基本的に辞書をセットアップすることです
数はコードを1000000回実行することです。セットアップではなく、stmt
これを実行すると、インデックスが取得よりもはるかに高速であることがわかります。複数回実行して確認できます。
このコードは基本的に、辞書の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
コード全体をtimeitの引数として渡すだけです。
import timeit
print(timeit.timeit(
"""
limit = 10000
prime_list = [i for i in range(2, limit+1)]
for prime in prime_list:
for elem in range(prime*2, max(prime_list)+1, prime):
if elem in prime_list:
prime_list.remove(elem)
"""
, number=10))
import timeit
def oct(x):
return x*x
timeit.Timer("for x in range(100): oct(x)", "gc.enable()").timeit()
gc.enable()
?
組み込みのtimeitモジュールは、IPythonコマンドラインから最適に機能します。
モジュール内から関数の時間を計るには:
from timeit import default_timer as timer
import sys
def timefunc(func, *args, **kwargs):
"""Time a function.
args:
iterations=3
Usage example:
timeit(myfunc, 1, b=2)
"""
try:
iterations = kwargs.pop('iterations')
except KeyError:
iterations = 3
elapsed = sys.maxsize
for _ in range(iterations):
start = timer()
result = func(*args, **kwargs)
elapsed = min(timer() - start, elapsed)
print(('Best of {} {}(): {:.9f}'.format(iterations, func.__name__, elapsed)))
return result
パラメーターを受け入れる関数でPython REPLインタープリターを使用する方法の例。
>>> import timeit
>>> def naive_func(x):
... a = 0
... for i in range(a):
... a += i
... return a
>>> def wrapper(func, *args, **kwargs):
... def wrapper():
... return func(*args, **kwargs)
... return wrapper
>>> wrapped = wrapper(naive_func, 1_000)
>>> timeit.timeit(wrapped, number=1_000_000)
0.4458435332577161
2つの関数を作成してから、これに似たものを実行します。リンゴとリンゴを比較するために、同じ数の実行/実行を選択したいことに注意してください。
これはPython 3.7でテストされました。
!/usr/local/bin/python3
import timeit
def fibonacci(n):
"""
Returns the n-th Fibonacci number.
"""
if(n == 0):
result = 0
elif(n == 1):
result = 1
else:
result = fibonacci(n-1) + fibonacci(n-2)
return result
if __name__ == '__main__':
import timeit
t1 = timeit.Timer("fibonacci(13)", "from __main__ import fibonacci")
print("fibonacci ran:",t1.timeit(number=1000), "milliseconds")
timsort(a)
、違いを確認してください:-)