468 Stimmen

Wie man das timeit-Modul verwendet

Wie verwende ich timeit um die Leistung meiner eigenen Funktionen wie " insertion_sort " und " tim_sort "?

347voto

Sven Marnach Punkte 525472

Wenn Sie Folgendes verwenden möchten timeit in einer interaktiven Python-Sitzung zu verwenden, gibt es zwei praktische Optionen:

  1. Verwenden Sie die IPython Schale. Sie verfügt über die praktische %timeit besondere Funktion:

    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. In einem Standard-Python-Interpreter können Sie auf Funktionen und andere Namen zugreifen, die Sie zuvor während der interaktiven Sitzung definiert haben, indem Sie sie von __main__ in der Setup-Anweisung:

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

323voto

Raymond Hettinger Punkte 197261

Der Weg timeit besteht darin, den Einrichtungscode einmal auszuführen und dann wiederholt eine Reihe von Anweisungen aufzurufen. Wenn Sie also die Sortierung testen wollen, müssen Sie darauf achten, dass ein Durchlauf einer In-Place-Sortierung nicht den nächsten Durchlauf mit bereits sortierten Daten beeinflusst (das würde natürlich die Timsort wirklich glänzen, weil es am besten funktioniert, wenn die Daten bereits teilweise geordnet sind).

Das folgende Beispiel zeigt, wie man einen Test für die Sortierung einrichtet:

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

Beachten Sie, dass die Anweisungsreihe bei jedem Durchlauf eine neue Kopie der unsortierten Daten erstellt.

Beachten Sie auch die Zeitmessungstechnik, bei der die Messsuite siebenmal ausgeführt wird und nur die beste Zeit gespeichert wird - dies kann wirklich dazu beitragen, Messverzerrungen aufgrund anderer auf Ihrem System laufender Prozesse zu reduzieren.

Das sind meine Tipps für die richtige Verwendung von timeit. Ich hoffe, das hilft :-)

193voto

Veedrac Punkte 54089

Ich verrate Ihnen ein Geheimnis: Der beste Weg, die timeit in der Befehlszeile steht.

In der Befehlszeile, timeit macht eine ordentliche statistische Analyse: Sie sagt Ihnen, wie lange der kürzeste Lauf gedauert hat. Das ist gut, denn todo Fehler bei der Zeitmessung positiv ist. Die kürzeste Zeit hat also den geringsten Fehler. Es gibt keine Möglichkeit, einen negativen Fehler zu erhalten, da ein Computer niemals schneller rechnen kann als er rechnen kann!

Also, die Befehlszeilenschnittstelle:

%~> python -m timeit "1 + 2"
10000000 loops, best of 3: 0.0468 usec per loop

Das ist doch ganz einfach, oder?

Sie können Dinge einrichten:

%~> python -m timeit -s "x = range(10000)" "sum(x)"
1000 loops, best of 3: 543 usec per loop

was auch nützlich ist!

Wenn Sie mehrere Zeilen benötigen, können Sie entweder die automatische Fortsetzung der Shell verwenden oder separate Argumente angeben:

%~> python -m timeit -s "x = range(10000)" -s "y = range(100)" "sum(x)" "min(y)"
1000 loops, best of 3: 554 usec per loop

Das ergibt eine Aufstellung von

x = range(1000)
y = range(100)

und Zeiten

sum(x)
min(y)

Wenn Sie längere Skripte haben möchten, könnten Sie versucht sein, zu timeit innerhalb eines Python-Skripts. Ich schlage vor, dies zu vermeiden, da die Analyse und das Timing in der Kommandozeile einfach besser sind. Stattdessen neige ich dazu, Shell-Skripte zu erstellen:

 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

Dies kann aufgrund der mehrfachen Initialisierungen etwas länger dauern, aber normalerweise ist das kein großes Problem.


Was aber, wenn Sie wollen zu verwenden timeit innerhalb Ihres Moduls?

Nun, der einfachste Weg ist zu tun:

def function(...):
    ...

timeit.Timer(function).timeit(number=NUMBER)

und das ergibt kumulativ ( pas Minimum!) Zeit für diese Anzahl von Durchläufen.

Um eine gute Analyse zu erhalten, verwenden Sie .repeat und nehmen Sie das Minimum:

min(timeit.Timer(function).repeat(repeat=REPEATS, number=NUMBER))

Normalerweise sollten Sie dies kombinieren mit functools.partial anstelle von lambda: ... um die Gemeinkosten zu senken. Man könnte also etwas wie folgt haben:

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

Das können Sie auch tun:

timeit.timeit("...", setup="from __main__ import ...", number=NUMBER)

das würde Ihnen etwas geben, das näher am Schnittstelle von der Kommandozeile aus, aber auf eine viel weniger coole Art und Weise. Die "from __main__ import ..." können Sie Code aus Ihrem Hauptmodul in der künstlichen Umgebung verwenden, die von timeit .

Es ist erwähnenswert, dass dies ein bequemer Wrapper für Timer(...).timeit(...) und ist daher nicht besonders gut im Timing. Ich persönlich bevorzuge bei weitem die Verwendung von Timer(...).repeat(...) wie ich oben gezeigt habe.


Warnungen

Es gibt ein paar Vorbehalte bei timeit die überall gelten.

  • Gemeinkosten werden nicht berücksichtigt. Angenommen, Sie wollen die Zeit x += 1 , um herauszufinden, wie lange die Addition dauert:

    >>> python -m timeit -s "x = 0" "x += 1"
    10000000 loops, best of 3: 0.0476 usec per loop

    Nun, es ist pas 0,0476 µs. Sie wissen nur, dass es sich um weniger als das. Jeder Fehler ist positiv.

    Versuchen Sie also zu finden rein Overhead:

    >>> python -m timeit -s "x = 0" ""      
    100000000 loops, best of 3: 0.014 usec per loop

    Das ist eine gute 30% Overhead nur vom Timing her! Dies kann die relativen Zeitangaben massiv verzögern. Aber Sie interessierten sich nur für die Hinzufügen von Timings; die Look-up-Timings für x müssen ebenfalls in die Gemeinkosten einbezogen werden:

    >>> python -m timeit -s "x = 0" "x"
    100000000 loops, best of 3: 0.0166 usec per loop

    Der Unterschied ist nicht viel größer, aber er ist da.

  • Mutierende Methoden sind gefährlich.

    >>> python -m timeit -s "x = [0]*100000" "while x: x.pop()"
    10000000 loops, best of 3: 0.0436 usec per loop

    Aber das ist völlig falsch! x ist die leere Liste nach der ersten Iteration. Sie müssen sie neu initialisieren:

    >>> python -m timeit "x = [0]*100000" "while x: x.pop()"
    100 loops, best of 3: 9.79 msec per loop

    Aber dann haben Sie eine Menge Aufwand. Das müssen Sie gesondert berücksichtigen.

    >>> python -m timeit "x = [0]*100000"                   
    1000 loops, best of 3: 261 usec per loop

    Beachten Sie, dass der Abzug der Gemeinkosten hier sinnvoll ist nur weil der Overhead macht nur einen Bruchteil der Zeit aus.

    Für Ihr Beispiel sei angemerkt, dass beide Einfügungssortierung und Zeitsortierung haben völlig unüblich Timing-Verhalten für bereits sortierte Listen. Dies bedeutet, dass Sie eine random.shuffle zwischen den einzelnen Sorten, wenn Sie Ihre Zeitplanung nicht durcheinander bringen wollen.

139voto

zzart Punkte 10506

Wenn Sie zwei Codeblöcke/Funktionen schnell vergleichen wollen, können Sie das tun:

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)

51voto

unutbu Punkte 769083

Ich finde, dass timeit am einfachsten über die Befehlszeile zu benutzen ist:

Gegeben test.py :

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

timeit auf diese Weise ausführen:

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

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X