web-dev-qa-db-ja.com

timeitモジュールの使い方

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

insertion_sorttim_sortの2つの関数をtimeitと比較するにはどうすればよいですか。

300
Neemaximo

方法timeitは、セットアップコードを1回実行してから、一連のステートメントを繰り返し呼び出すことです。そのため、ソートをテストしたい場合は、インプレースソートでの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を正しく使うための私のヒントです。お役に立てれば :-)

243

対話的な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. 標準のPythonインタプリタでは、setupステートメントの__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]
    
239
Sven Marnach

timeitを使う最善の方法はコマンドラインです。

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

だから、コマンドラインインターフェイス:

%~> 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)

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

 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)

そしてそれはあなたにその回数を実行するための累積(notminimum!)時間を与えます。

良い分析を得るために、.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)

これは、コマンドラインからinterfaceに近いものにしますが、それほどクールではありません。 "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
    

    まあ、それはnot0.0476 µsです。あなたはそれがlessであることだけを知っています。すべての誤差は正です。

    それでpure間接費を見つけてみてください。

    >>> 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
    

    でオーバーヘッドを差し引くのが合理的であることに注意してください。これは、オーバーヘッドはごくわずかな時間であるためです。

    あなたの例では、bothInsert SortとTim Sortのタイミングがまったく変わっていないソート済みリストの動作これは、タイミングを壊したくない場合は、ソート間にrandom.shuffleが必要になることを意味します。

117
Veedrac

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)
82
zzart

Timeitを使う最も簡単な方法はコマンドラインからです。

与えられたtest.py

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

このようにtimeitを実行します。

% python -mtimeit -s'import test' 'test.InsertionSort()'
% python -mtimeit -s'import test' 'test.TimSort()'
41
unutbu

私にとっては、これが最も速い方法です。

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


timeit.timeit(stmt=foo, number=1234567)
12
Rodrigo Laguna
# Генерация целых чисел

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)
11
David Webb

これはとてもうまくいきます。

  python -m timeit -c "$(cat file_name.py)"
7
Ohad Rubin

以下のそれぞれで同じ辞書を設定し、実行時間をテストしましょう。

Setup引数は基本的に辞書を設定することです

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

これを実行すると、インデックスが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

3
Stryker

コード全体を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()
0
Yagmur SAHIN

2つの関数を作成してから、これに似たものを実行します。 AppleとAppleを比較するために、同じ数の実行/実行を選択する必要があります。
これはPython 3.7でテストされました。

enter image description here これをコピーしやすくするためのコードです。

!/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 __== '__main__':
    import timeit
    t1 = timeit.Timer("fibonacci(13)", "from __main__ import fibonacci")
    print("fibonacci ran:",t1.timeit(number=1000), "milliseconds")
0
grepit

組み込みの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
0
ChaimG

パラメータを受け取る関数で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                                                                                        
0
Vlad Bezden