web-dev-qa-db-ja.com

pythonの関数の正確なタイミング

私はWindowsでpythonでプログラミングしています。関数が実行されるのにかかる時間を正確に測定したいと思います。別の関数を実行し、実行する関数 "time_it"実行にかかった時間を返します。

def time_it(f, *args):
    start = time.clock()
    f(*args)
    return (time.clock() - start)*1000

これを1000回呼び出して、結果を平均します。 (最後の1000定数は、ミリ秒単位で答えを与えることです。)

この関数は機能しているように見えますが、私は何か間違ったことをしているというしつこい感じがあります。

これを行うためのより標準的なまたは受け入れられた方法はありますか?

時間がかかるようにテスト関数を変更してprintを呼び出すと、time_it関数は平均2.5ミリ秒を返しますが、cProfile.run( 'f()')は平均7.0ミリ秒を返します。私は自分の機能が時間を過大評価していると考えましたが、ここで何が起こっていますか?

もう1つの注意点は、ハードウェアやその他の要因によって明らかに変化する絶対時間ではなく、相互に比較される機能の相対時間です。

62
Atilio Jobson

独自のプロファイリングコードを記述する代わりに、組み込みのPythonプロファイラー(必要に応じてprofileまたはcProfile)を確認することをお勧めします。 http://docs.python.org/library/profile.html

37
Daniel Lew

Python標準ライブラリから timeitモジュール を使用します。

基本的な使用法:

from timeit import Timer

# first argument is the code to be run, the second "setup" argument is only run once,
# and it not included in the execution time.
t = Timer("""x.index(123)""", setup="""x = range(1000)""")

print t.timeit() # prints float, for example 5.8254
# ..or..
print t.timeit(1000) # repeat 1000 times instead of the default 1million
69
Alex Martelli

次のような「timeme」デコレータを作成できます

import time                                                

def timeme(method):
    def wrapper(*args, **kw):
        startTime = int(round(time.time() * 1000))
        result = method(*args, **kw)
        endTime = int(round(time.time() * 1000))

        print(endTime - startTime,'ms')
        return result

    return wrapper

@timeme
def func1(a,b,c = 'c',sleep = 1):
    time.sleep(sleep)
    print(a,b,c)

func1('a','b','c',0)
func1('a','b','c',0.5)
func1('a','b','c',0.6)
func1('a','b','c',1)
30
vdrmrt

このコードは非常に不正確です

total= 0
for i in range(1000):
    start= time.clock()
    function()
    end= time.clock()
    total += end-start
time= total/1000

このコードはそれほど正確ではありません

start= time.clock()
for i in range(1000):
    function()
end= time.clock()
time= (end-start)/1000

関数の実行時間がクロックの精度に近い場合、非常に不正確な測定バイアスに悩まされます。測定された時間のほとんどは、0からクロックの数ティックの間の単なる乱数です。

システムのワークロードに応じて、単一の機能から観察される「時間」は、OSスケジューリングおよびその他の制御不能なオーバーヘッドの完全な成果物である場合があります。

2番目のバージョン(あまり正確ではない)の測定バイアスは小さくなっています。関数が非常に高速な場合、OSスケジューリングやその他のオーバーヘッドを抑えるために10,000回実行する必要があるかもしれません。

もちろん、どちらもひどく誤解を招きます。プログラムの実行時間(全体として)は、関数の実行時間の合計ではありません。数値は相対比較にのみ使用できます。それらは多くの意味を伝える絶対的な測定値ではありません。

23
S.Lott

計測するブロックがスローされる可能性がある場合でもpythonメソッドの時間を計る場合、1つの良いアプローチはwithステートメントを使用することです。いくつかのTimerクラスを

_import time

class Timer:    
    def __enter__(self):
        self.start = time.clock()
        return self

    def __exit__(self, *args):
        self.end = time.clock()
        self.interval = self.end - self.start
_

次に、スローする可能性のある接続メソッドの時間を計る必要があります。つかいます

_import httplib

with Timer() as t:
    conn = httplib.HTTPConnection('google.com')
    conn.request('GET', '/')

print('Request took %.03f sec.' % t.interval)
_

__exit()__メソッドは、接続要求が処理されても呼び出されます。より正確には、tryfinallyを使用して、スローした場合の結果を確認する必要があります。

_try:
    with Timer() as t:
        conn = httplib.HTTPConnection('google.com')
        conn.request('GET', '/')
finally:
    print('Request took %.03f sec.' % t.interval)
_

詳細はこちら

14
kiriloff

これはすてきです

from contextlib import contextmanager

import time
@contextmanager
def timeblock(label):
    start = time.clock()
    try:
        yield
    finally:
        end = time.clock()
        print ('{} : {}'.format(label, end - start))



with timeblock("just a test"):
            print "yippee"
7
JasonEdinburgh

@AlexMartelliの答えに似ています

import timeit
timeit.timeit(fun, number=10000)

トリックを行うことができます。

4
Binu Jasim