2016-03-22 21 views
1

Sagen wir, ich versuche, die Ausführungszeit einer Sortierfunktion zu messen, hier ist mein Code:Python Zeit: Wie initialisiert man vor jeder Wiederholung Argumente für die zeitgesteuerte Funktion?

import timeit 

def time_algo(sort_fun, input_seq, num=100): 
    ''' 
    Time how long it takes to sort sequence 'input_seq' using 
    function 'sort_fun'. Take min of 'num' times. 
    ''' 
    foo = list(input_seq) 
    wrapped = wrapper(sort_fun, foo) 
    return min(timeit.repeat(wrapped, repeat=num, number=1)) 

def wrapper(func, *args): 
    def wrapped(): 
     return func(*args) 
    return wrapped 

print time_algo(list.sort, [10,9,8,7,6,5,4,3,2,1], num = 100) 

Das Problem ist, dass nach der ersten Ausführung von sort_fun wird die Eingangsliste bereits sortiert, und es ist läuft auf einer sortierten Liste für den Rest von num - 1 mal.

Wie kann ich die Argumente für die Eingabefunktion initialisieren (in diesem Fall execute foo = list(input_seq)) vor jeder Wiederholung der Funktion Timing? Oder was wäre der richtige Weg, dies mit dem timeit Modul zu tun (Ich brauche genaue Ergebnisse, damit ich keine anderen Zeitmessmethoden wie time.clock() usw. verwenden möchte)?

+0

Stört es Sie, wenn die Zeit für eine Kopie im Timing-Ergebnis enthalten ist? – MSeifert

+0

Genau das versuche ich hier zu vermeiden :) –

+0

Das wird schwer. Sie möchten, dass Ihre zu testende Funktion ihre Argumente nicht ändert. Oder Sie müssen für jeden Anruf eine Kopie erstellen. Aber solange die Funktion nicht viel Zeit benötigt, kann man (oder die timeit-Implementierung) das Timing nicht bei jedem Aufruf starten und stoppen, es ist zu kurz, das ist der Punkt von 'num> 1'. – Pierce

Antwort

3

Ich denke, das modifizierte time_algo() tut, was Sie wollen:

def time_algo(sort_fun, input_seq, num=100):               
    '''                        
    Time how long it takes to sort sequence 'input_seq' using          
    function 'sort_fun'. Take min of 'num' times.             
    '''                        
    foo = list(input_seq)                   
    wrapped = wrapper(sort_fun, foo)                 
    def reset_foo():                     
     foo[:] = list(input_seq)                  
    return min(timeit.timeit(wrapped, setup=reset_foo, number=1) for _ in range(num)) 

Diese erneuten Kopien input_seq vor jeder timeit (foo zur Liste). Es gibt weniger fancy/mehr manuelle Möglichkeiten, es zu tun, die allgemeiner sein könnten: Sie könnten eine einfache Schleife schreiben, die die Eingabe kopiert, einen neuen Wrapper erstellt und timeit aufruft.

... aber wie oben erwähnt, möchten Sie wirklich mehrere Iterationen pro Zeiteinheit, und dafür möchten Sie wirklich eine Funktion zeitlich steuern, die ihre Eingaben nicht ändert.

+0

Danke für die Antwort, es ist nicht schön, aber es sieht so aus, als würde es tun, wonach ich gefragt habe. Übrigens, meinst du, dass das Einbeziehen des Kopierzeitpunkts und das Erhöhen des Zahlparameters in der Zeitfunktion mir zuverlässigere Ergebnisse liefern, oder das ist der Weg zu gehen? Für mich sieht das zumindest theoretisch besser aus. –

+0

Es kommt darauf an, wie lange deine Funktion dauert, um an einem realistischen Testeingang zu arbeiten. Wenn es eine "lange" Zeit braucht (vielleicht 10 Millisekunden oder mehr), ist das obige wahrscheinlich in Ordnung. Wenn es nicht so lange dauert, aber viele Male ausgeführt wird (in Ihrem Anwendungsfall), dann ist das Sammeln/Kopieren von Eingaben wahrscheinlich signifikanter, das sollte realistisch sein und in der zeitgesteuerten Funktion enthalten sein. Wenn es nicht lange dauert und nicht oft läuft, ist es egal. – Pierce