Abrufen der Ausführungszeit eines Codeblocks in Python 2.7

78

Ich möchte die verstrichene Zeit messen, um einen Codeblock in einem Python-Programm auszuwerten, wobei möglicherweise zwischen Benutzer-CPU-Zeit, System-CPU-Zeit und verstrichener Zeit getrennt wird.

Ich kenne das timeitModul, aber ich habe viele selbstgeschriebene Funktionen und es ist nicht sehr einfach, sie im Setup-Prozess zu übergeben.

Ich hätte lieber etwas, das verwendet werden könnte wie:

#up to here I have done something....
start_counting() #or whatever command used to mark that I want to measure
                   #the time elapsed in the next rows
# code I want to evaluate
user,system,elapsed = stop_counting() #or whatever command says:
                                      #stop the timer and return the times

Die Benutzer- und System-CPU-Zeiten sind nicht wesentlich (obwohl ich sie messen möchte), aber für die verstrichene Zeit möchte ich in der Lage sein, so etwas zu tun, anstatt komplizierte Befehle oder Module zu verwenden.

Lucaceron
quelle

Antworten:

164

Um die verstrichene Zeit in Sekunden zu erhalten, können Sie Folgendes verwenden timeit.default_timer():

import timeit
start_time = timeit.default_timer()
# code you want to evaluate
elapsed = timeit.default_timer() - start_time

timeit.default_timer()wird anstelle von time.time()oder verwendet, time.clock()weil die Timing-Funktion ausgewählt wird, die für jede Plattform die höhere Auflösung aufweist.

Andrew Clark
quelle
4
Ich habe gelesen, dass dies nicht der beste Ansatz für Codeblöcke ist, deren Ausführung nur einen Bruchteil einer Sekunde dauert. Auch denke ich, dass mit dem Zeitmodul die .clock () -Methode bevorzugt wird? stackoverflow.com/questions/85451/…
Lucacerone
4
Meine Antwort wurde geändert, um zu verwenden timeit.default_timer(), wobei zwischen time.time()oder time.clock()je nachdem, welche Auflösung auf der von Ihnen verwendeten Plattform höher ist.
Andrew Clark
24

Ich benutze immer einen Dekorateur, um zusätzliche Arbeit für eine vorhandene Funktion zu erledigen, einschließlich der Ausführungszeit. Es ist pythonisch und einfach.

import time

def time_usage(func):
    def wrapper(*args, **kwargs):
        beg_ts = time.time()
        retval = func(*args, **kwargs)
        end_ts = time.time()
        print("elapsed time: %f" % (end_ts - beg_ts))
        return retval
    return wrapper

@time_usage
def test():
    for i in xrange(0, 10000):
        pass

if __name__ == "__main__":
    test()
Yarkee
quelle
3
Es tut mir leid, ich weiß immer noch nicht, wie man Dekorateure benutzt :(
Lucacerone
4
@LucaCerone gibt es eine ausgezeichnete Erklärung für Dekoration stackoverflow.com/questions/739654/… . Versuchen Sie es geduldig zu lesen und Sie werden Dekorateur verstehen.
Yarkee
Fügen Sie möglicherweise ein retval=...und return retvalzum Wrapper hinzu. Wenn Sie den Dekorator unverändert verwenden, werden die Rückgabewerte von func verworfen.
Dave X
10

Ich habe dieses Problem immer wieder gelöst und schließlich eine Bibliothek dafür erstellt. Installieren mit pip install timer_cm. Dann:

from time import sleep
from timer_cm import Timer

with Timer('Long task') as timer:
    with timer.child('First step'):
        sleep(1)
    for _ in range(5):
        with timer.child('Baby steps'):
            sleep(.5)

Ausgabe:

Long task: 3.520s
  Baby steps: 2.518s (71%)
  First step: 1.001s (28%)
Michael Herrmann
quelle
Eine scheinbar relevante Frage, die ich aufgeworfen habe: stackoverflow.com/questions/48260833/…
lurix66
Funktioniert hervorragend, außer einem Tippfehler ('Timer importieren' ---> 'Timer importieren') und einem fehlenden Paket ( import time)
user3768495
Das ist fantastisch. Ich habe ein Github-Problem in Ihrem Repo mit einem Stub erstellt, den die Leute beim Importieren verwenden können, wenn sie es optional machen möchten.
Craig Ringer
9

Sie können dies über den Kontext-Manager erreichen, zum Beispiel:

from contextlib import contextmanager
import time
import logging
@contextmanager
def _log_time_usage(prefix=""):
    '''log the time usage in a code block
    prefix: the prefix text to show
    '''
    start = time.time()
    try:
        yield
    finally:
        end = time.time()
        elapsed_seconds = float("%.2f" % (end - start))
        logging.debug('%s: elapsed seconds: %s', prefix, elapsed_seconds)

Anwendungsbeispiel:

with _log_time_usage("sleep 1: "):
    time.sleep(1)
monklof
quelle
Es sollte prefixnicht item_name in der letzten Zeile stehen.
George Petrov
1

Es gibt noch eine Option, die ich der Einfachheit halber sehr liebe - ipython. In ipython gibt es viele nützliche Dinge plus:

%time <expression> - um gerade CPU und Wandzeit auf Ausdruck zu bekommen

%timeit <expression> - um CPU und Wandzeit in einer Ausdrucksschleife zu erhalten

Valex
quelle
0

Python 3 - Einfache Lösung mit Standardbibliothek

Option 1: Dreifach den Code zitieren

import inspect
import timeit


code_block = inspect.cleandoc("""
    base = 123456789
    exponent = 100
    return base ** exponent
    """)
print(f'\Code block: {timeit.timeit(code_block, number=1, globals=globals())} elapsed seconds')

inspect.cleandoc übernimmt das Entfernen zusätzlicher Tabulatoren und Leerzeichen, sodass Codeblöcke kopiert und eingefügt werden können, ohne dass Einrückungsfehler auftreten.

 

Option 2: Codeblock in eine Funktion einfügen

import timeit


def my_function():
    base = 123456789
    exponent = 100
    return base ** exponent


if __name__ == '__main__':
    print(f'With lambda wrapper: {timeit.timeit(lambda: my_function(), number=1)} elapsed seconds')

Beachten Sie, dass ein Funktionsaufruf zusätzliche Ausführungszeit gegenüber dem direkten Timing des Funktionskörpers hinzufügt.

Christopher Peisert
quelle