Python時間測定関数


121

各関数で費やされた時間をテストし、その名前をその時間とともに印刷するPython関数を作成したい、関数名を印刷する方法、および他に方法がある場合は教えてください

def measureTime(a):
    start = time.clock() 
    a()
    elapsed = time.clock()
    elapsed = elapsed - start
    print "Time spent in (function name) is: ", elapsed

Pythonプロファイリングツールは、関数名とそれぞれに費やされた時間を表示できます。ここをお読みください:docs.python.org/library/profile.html
Roadmaster

timeit測定のためのより良い使用。それは完璧ではありませんが、それはあなたの突き刺しをはるかにtimeit上回っており、より良いものを自分で作るよりもはるかに使いやすいです。

回答:


240

何よりもまず、プロファイラーまたは少なくとも使用時間を使用することを強くお勧めします。

ただし、独自のタイミングメソッドを厳密に記述して学習したい場合は、ここにデコレータの使用を開始する場所があります。

Python 2:

def timing(f):
    def wrap(*args):
        time1 = time.time()
        ret = f(*args)
        time2 = time.time()
        print '%s function took %0.3f ms' % (f.func_name, (time2-time1)*1000.0)
        return ret
    return wrap

使い方は非常に簡単です。@ timingデコレータを使用するだけです。

@timing
def do_work():
  #code

Python 3:

def timing(f):
    def wrap(*args, **kwargs):
        time1 = time.time()
        ret = f(*args, **kwargs)
        time2 = time.time()
        print('{:s} function took {:.3f} ms'.format(f.__name__, (time2-time1)*1000.0))

        return ret
    return wrap

注意:f.func_name関数名を文字列として取得するために呼び出しています(Python 2)、またはf.__name__ Python 3。


4
まさに私が欲しいものです:) ...しかし、皆さんは私にpythonプロファイラーを使用するように納得させました
Wazery

3
これは、time.time()がエポックからの時間をマイクロ秒で報告すると想定しているように見えますか?ドキュメントには、秒単位の時間docs.python.org/2/library/time.html#time.timeが報告されると記載されています。
Rahul Jha 14

funcでyieldを使用すると、これは有効になりません。この方法を使用して収量を使用するにはどうすればよいですか?
ジャモ

def timing(f):def wrap(* args、** kwargs):time1 = time.time()ret = f(* args、** kwargs)time2 = time.time()print '%s関数は%0.3かかりましたf ms '%(f.func_name、(time2-time1)* 1000)return ret return wrap
Vivek Bagaria

1
自分で書くことの欠点は何ですか?経過時間のリストを保存し、それらの分布を調べるのは十分簡単ではありませんか?
2018年

51

timeitモジュールで遊んだ後、私はそのインターフェースが好きではありません。それは、次の2つの方法と比較してそれほどエレガントではありません。

次のコードはPython 3に含まれています。

デコレータメソッド

これは、@ Mikeのメソッドとほとんど同じです。ここに追加kwargsしてfunctoolsラップし、より良いものにします。

def timeit(func):
    @functools.wraps(func)
    def newfunc(*args, **kwargs):
        startTime = time.time()
        func(*args, **kwargs)
        elapsedTime = time.time() - startTime
        print('function [{}] finished in {} ms'.format(
            func.__name__, int(elapsedTime * 1000)))
    return newfunc

@timeit
def foobar():
    mike = Person()
    mike.think(30)

コンテキストマネージャメソッド

from contextlib import contextmanager

@contextmanager
def timeit_context(name):
    startTime = time.time()
    yield
    elapsedTime = time.time() - startTime
    print('[{}] finished in {} ms'.format(name, int(elapsedTime * 1000)))

たとえば、次のように使用できます。

with timeit_context('My profiling code'):
    mike = Person()
    mike.think()

そして、withブロック内のコードはタイミングがとられます。

結論

最初の方法を使用すると、デコレーターをコメントアウトして通常のコードを取得できます。ただし、それは関数の時間しか計測できません。コードの一部を関数にしたくない場合は、2番目の方法を選択できます。

たとえば、今

images = get_images()
bigImage = ImagePacker.pack(images, width=4096)
drawer.draw(bigImage)

今、あなたはbigImage = ...ラインを計りたいです。関数に変更すると、次のようになります。

images = get_images()
bitImage = None
@timeit
def foobar():
    nonlocal bigImage
    bigImage = ImagePacker.pack(images, width=4096)
drawer.draw(bigImage)

見た目はそれほど良くない...あなたがPython 2を使っていて、nonlocalキーワードがない場合はどうでしょう。

代わりに、2番目の方法を使用すると、非常にうまく適合します。

images = get_images()
with timeit_context('foobar'):
    bigImage = ImagePacker.pack(images, width=4096)
drawer.draw(bigImage)

興味深い貢献ですが、あなたが述べたデコレーターメソッドでは、timeitインターフェイスを変更しwraps()functoolsモジュールの関数を使用する必要があったことは役に立たないことがわかりました。つまり、追加のコードは必要ありません。
Billal Begueradj 2017

1
ニーズimport functools
ギヨームシュヴァリエ

1
デコレータが元の関数の戻り値を失うことに注意してください
Marc Van Daele

11

timeitモジュールの何が問題なのかわかりません。これはおそらく、最も簡単な方法です。

import timeit
timeit.timeit(a, number=1)

関数に引数を送ることも可能です。必要なのは、デコレータを使用して関数をラップすることだけです。詳細はこちら: http //www.pythoncentral.io/time-a-python-function/

独自のタイミングステートメントを書くことに関心があるのは、関数を1回だけ実行し、その戻り値も取得したい場合だけです。

timeitモジュールを使用する利点は 、実行回数を繰り返すことができることです。他のプロセスがタイミングの精度を妨げる可能性があるため、これが必要になる場合があります。したがって、それを複数回実行して、最低値を確認する必要があります。


3
ラッパーとデコレーターを使用して関数に引数を送信しますか?なんでtimeit.timeit(lambda: func(a,b,c), number=1)?端末で仮想ソリューションのテストを行うときにこれを使用します。
ジャック

10

Timeitには2つの大きな欠陥があります。関数の戻り値を返さないことと、インポートに追加のセットアップコードを渡す必要があるevalを使用することです。これにより、両方の問題が簡単かつエレガントに解決されます。

def timed(f):
  start = time.time()
  ret = f()
  elapsed = time.time() - start
  return ret, elapsed

timed(lambda: database.foo.execute('select count(*) from source.apachelog'))
(<sqlalchemy.engine.result.ResultProxy object at 0x7fd6c20fc690>, 4.07547402381897)

ありがとう!すべてのSpark依存関係をインポートする必要があるため、Apache Sparkではtimeitはうまく機能しません。それを行う古い古い文字列を作成したいのは誰ですか?このソリューションは、はるかにシンプルで柔軟です。
Paul

4

タイミングのための簡単なツールがあります。https://github.com/RalphMao/PyTimer

それはデコレータのように働くことができます:

from pytimer import Timer
@Timer(average=False)      
def matmul(a,b, times=100):
    for i in range(times):
        np.dot(a,b)        

出力:

matmul:0.368434
matmul:2.839355

また、ネームスペースコントロールを備えたプラグインタイマーのように機能することもできます(多くのコードがあり、他の場所から呼び出される可能性がある関数に挿入する場合に役立ちます)。

timer = Timer()                                           
def any_function():                                       
    timer.start()                                         

    for i in range(10):                                   

        timer.reset()                                     
        np.dot(np.ones((100,1000)), np.zeros((1000,500)))
        timer.checkpoint('block1')                        

        np.dot(np.ones((100,1000)), np.zeros((1000,500)))
        np.dot(np.ones((100,1000)), np.zeros((1000,500)))
        timer.checkpoint('block2')                        
        np.dot(np.ones((100,1000)), np.zeros((1000,1000)))

    for j in range(20):                                   
        np.dot(np.ones((100,1000)), np.zeros((1000,500)))
    timer.summary()                                       

for i in range(2):                                        
    any_function()                                        

出力:

========Timing Summary of Default Timer========
block2:0.065062
block1:0.032529
========Timing Summary of Default Timer========
block2:0.065838
block1:0.032891

それが役に立てば幸い


3

デコレータPythonライブラリを使用したデコレータメソッド:

import decorator

@decorator
def timing(func, *args, **kwargs):
    '''Function timing wrapper
        Example of using:
        ``@timing()``
    '''

    fn = '%s.%s' % (func.__module__, func.__name__)

    timer = Timer()
    with timer:
        ret = func(*args, **kwargs)

    log.info(u'%s - %0.3f sec' % (fn, timer.duration_in_seconds()))
    return ret

私のブログの投稿を参照してください:

mobilepro.plブログへの投稿

Google Plusへの私の投稿


1

それを行う私の方法:

from time import time

def printTime(start):
    end = time()
    duration = end - start
    if duration < 60:
        return "used: " + str(round(duration, 2)) + "s."
    else:
        mins = int(duration / 60)
        secs = round(duration % 60, 2)
        if mins < 60:
            return "used: " + str(mins) + "m " + str(secs) + "s."
        else:
            hours = int(duration / 3600)
            mins = mins % 60
            return "used: " + str(hours) + "h " + str(mins) + "m " + str(secs) + "s."

start = time()前に関数/ループを実行しprintTime(start)、ブロックの直後に変数を設定します。

そしてあなたは答えを得ました。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.