Frage

Ich versuche, einige Code zu Zeit. Zuerst habe ich eine Zeit Dekorateur:

#!/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.)

Ausbeuten

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

Und hier verwende ich 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

Mit timeit die Ergebnisse sind praktisch die gleichen, aber mit dem Timing Dekorateur es erscheint time_indexing ist schneller als time_izip.

Was ist die Ursache für diesen Unterschied?

Sollte eine Methode angenommen werden?

Wenn ja, welche?

War es hilfreich?

Lösung

Mit timeit. Durchführung des Tests mehr als einmal gibt mir viel bessere Ergebnisse.

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.

Andere Tipps

Mit Verpackung von functools Matt Alcock Antwort zu verbessern.

from functools import wraps
from time import time

def timing(f):
    @wraps(f)
    def wrap(*args, **kw):
        ts = time()
        result = f(*args, **kw)
        te = time()
        print 'func:%r args:[%r, %r] took: %2.4f sec' % \
          (f.__name__, args, kw, te-ts)
        return result
    return wrap

In einem Beispiel:

@timing
def f(a):
    for _ in range(a):
        i = 0
    return -1

Hervorrufen Methode f mit @timing gewickelt:

func:'f' args:[(100000000,), {}] took: 14.2240 sec
f(100000000)

Der Vorteil hierbei ist, dass es Attribute der ursprünglichen Funktion bewahrt; das heißt, Metadaten wie die Funktionsnamen und docstring korrekt auf der zurückgegebene Funktion erhalten bleibt.

Ich möchte einen Timing Dekorateur verwenden, da Sie Anmerkungen verwenden können das Timing um den Code zu streuen, anstatt dass Sie mit Timing-Logik chaotisch codieren.

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

die Dekorateur Verwendung ist einfach entweder Gebrauch Anmerkungen.

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

oder Wieder alias die Funktion, die Sie Zeit mögen.

compute_magic = timeit(compute_magic)

Ich habe genug von from __main__ import foo, jetzt diese verwenden - für die einfache args, für die% r Werke, und nicht in IPython.
(Warum timeit nur auf Strings arbeitet, nicht Thunks / Verschlüsse heißt timefunc (f, willkürliche 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 )

Hinzugefügt: siehe auch "ipython spielt seltsame Tricks mit Haupt ", Martelli in Einlauf Doctests-through-ipython

Nur eine Vermutung, aber könnte der Unterschied sein, die Größenordnung des Unterschieds in range () Werte?

Von Ihrer ursprünglichen Quelle:

alist=range(1000000)

Von Ihrem timeit Beispiel:

alist=range(100000)

Für das, was es wert ist, hier sind die Ergebnisse auf meinem System mit dem Bereich auf 1 Million:

$ 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

ich nicht in der Lage war Ihren anderen Code zu bekommen zu laufen, da ich nicht die „Dekorateur“ Modul auf meinem System importieren konnte.


Aktualisieren -. Ich sehe die gleiche Diskrepanz Sie tun, wenn ich den Code ohne den Dekorateur beteiligt laufen

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

Vielen Dank für die Buchung dieser Frage; Ich lernte etwas heute. =)

unabhängig von diesem speziellen Übung, würde ich mir vorstellen, dass timeit mit viel sicherer und zuverlässiger Option. es ist auch plattformübergreifende, im Gegensatz zu Ihrer Lösung.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top