87

私はいくつかのコードの時間を計ろうとしています。まず、タイミング デコレータを使用しました。

#!/usr/bin/env python

import time
from itertools import izip
from random import shuffle

def timing_val(func):
    def wrapper(*arg, **kw):
        '''source: http://www.daniweb.com/code/snippet368.html'''
        t1 = time.time()
        res = func(*arg, **kw)
        t2 = time.time()
        return (t2 - t1), res, func.__name__
    return wrapper

@timing_val
def time_izip(alist, n):
    i = iter(alist)
    return [x for x in izip(*[i] * n)]

@timing_val
def time_indexing(alist, n):
    return [alist[i:i + n] for i in range(0, len(alist), n)]

func_list = [locals()[key] for key in locals().keys()
             if callable(locals()[key]) and key.startswith('time')]
shuffle(func_list)  # Shuffle, just in case the order matters

alist = range(1000000)
times = []
for f in func_list:
    times.append(f(alist, 31))

times.sort(key=lambda x: x[0])
for (time, result, func_name) in times:
    print '%s took %0.3fms.' % (func_name, time * 1000.)

収量

% test.py
time_indexing took 73.230ms.
time_izip took 122.057ms.

ここで timeit を使用します。

%  python - m timeit - s '' 'alist=range(1000000);[alist[i:i+31] for i in range(0, len(alist), 31)]'
10 loops, best of 3:
    64 msec per loop
% python - m timeit - s 'from itertools import izip' 'alist=range(1000000);i=iter(alist);[x for x in izip(*[i]*31)]'
10 loops, best of 3:
    66.5 msec per loop

timeit を使用しても結果は実質的に同じですが、タイミング デコレータを使用するtime_indexingと よりも高速に表示されますtime_izip

この違いの原因は何ですか?

どちらの方法も信じるべきですか?

もしそうなら、どれ?

4

8 に答える 8

42

タイミング ロジックでコードを乱雑にするのではなく、注釈を使用してコードの周りにタイミングを振りかけることができるため、タイミング デコレータを使用します。

import time

def timeit(f):

    def timed(*args, **kw):

        ts = time.time()
        result = f(*args, **kw)
        te = time.time()

        print 'func:%r args:[%r, %r] took: %2.4f sec' % \
          (f.__name__, args, kw, te-ts)
        return result

    return timed

デコレーターの使用は、注釈を使用するか簡単です。

@timeit
def compute_magic(n):
     #function definition
     #....

または、時間を計測したい関数を再エイリアスします。

compute_magic = timeit(compute_magic)
于 2013-02-28T13:10:30.233 に答える
24

timeit を使用します。テストを複数回実行すると、はるかに良い結果が得られます。

func_list=[locals()[key] for key in locals().keys() 
           if callable(locals()[key]) and key.startswith('time')]

alist=range(1000000)
times=[]
for f in func_list:
    n = 10
    times.append( min(  t for t,_,_ in (f(alist,31) for i in range(n)))) 

for (time,func_name) in zip(times, func_list):
    print '%s took %0.3fms.' % (func_name, time*1000.)

->

<function wrapper at 0x01FCB5F0> took 39.000ms.
<function wrapper at 0x01FCB670> took 41.000ms.
于 2009-10-26T13:10:14.053 に答える
6

I got tired of from __main__ import foo, now use this -- for simple args, for which %r works, and not in Ipython.
(Why does timeit works only on strings, not thunks / closures i.e. timefunc( f, arbitrary args ) ?)


import timeit

def timef( funcname, *args, **kwargs ):
    """ timeit a func with args, e.g.
            for window in ( 3, 31, 63, 127, 255 ):
                timef( "filter", window, 0 )
    This doesn't work in ipython;
    see Martelli, "ipython plays weird tricks with __main__" in Stackoverflow        
    """
    argstr = ", ".join([ "%r" % a for a in args]) if args  else ""
    kwargstr = ", ".join([ "%s=%r" % (k,v) for k,v in kwargs.items()]) \
        if kwargs  else ""
    comma = ", " if (argstr and kwargstr)  else ""
    fargs = "%s(%s%s%s)" % (funcname, argstr, comma, kwargstr)
        # print "test timef:", fargs
    t = timeit.Timer( fargs, "from __main__ import %s" % funcname )
    ntime = 3
    print "%.0f usec %s" % (t.timeit( ntime ) * 1e6 / ntime, fargs)

#...............................................................................
if __name__ == "__main__":
    def f( *args, **kwargs ):
        pass

    try:
        from __main__ import f
    except:
        print "ipython plays weird tricks with __main__, timef won't work"
    timef( "f")
    timef( "f", 1 )
    timef( "f", """ a b """ )
    timef( "f", 1, 2 )
    timef( "f", x=3 )
    timef( "f", x=3 )
    timef( "f", 1, 2, x=3, y=4 )

Added: see also "ipython plays weird tricks with main", Martelli in running-doctests-through-ipython

于 2009-10-27T12:57:51.623 に答える
2

単なる推測ですが、違いは range() 値の違いの大きさのオーダーでしょうか?

元の情報源から:

alist=range(1000000)

あなたのtimeit例から:

alist=range(100000)

参考までに、範囲を 100 万に設定した私のシステムでの結果を次に示します。

$ python -V
Python 2.6.4rc2

$ python -m timeit -s 'from itertools import izip' 'alist=range(1000000);i=iter(alist);[x for x in izip(*[i]*31)]'
10 loops, best of 3: 69.6 msec per loop

$ python -m timeit -s '' 'alist=range(1000000);[alist[i:i+31] for i in range(0, len(alist), 31)]'
10 loops, best of 3: 67.6 msec per loop

システムに「decorator」モジュールをインポートできなかったため、他のコードを実行できませんでした。


更新- デコレータを使用せずにコードを実行すると、同じ不一致が見られます。

$ ./test.py
time_indexing took 84.846ms.
time_izip took 132.574ms.

この質問を投稿していただきありがとうございます。今日、私はあることを学びました。=)

于 2009-10-26T04:24:39.010 に答える
0

timeitこの特定の演習に関係なく、を使用する方がはるかに安全で信頼できるオプションであると思います。あなたのソリューションとは異なり、クロスプラットフォームでもあります。

于 2009-10-26T12:48:52.560 に答える