Verstrichene Zeit mit dem Zeitmodul messen

337

Ist es mit dem Zeitmodul in Python möglich, die verstrichene Zeit zu messen? Wenn ja, wie mache ich das?

Ich muss dies tun, damit ein Ereignis eintritt, wenn sich der Cursor für eine bestimmte Dauer in einem Widget befindet.

Rechteck
quelle
3
NB, dass jede Antwort mit time.time()falsch ist. Das einfachste Beispiel ist, wenn sich die Systemzeit während des Messzeitraums ändert.
OrangeDog
Für Ihre ursprüngliche Frage zum Auslösen eines Ereignisses, wenn ein Cursor für eine bestimmte Dauer in einem Widget verbleibt, bietet docs.python.org/3/library/threading.html meiner Meinung nach alles, was Sie benötigen. Multithreading und eine Bedingungsvariable mit Timeout könnten eine der Lösungen sein. Ihre Umstände sind derzeit jedoch unklar zu beantworten.
Tora
2
Es gibt keinen Grund, den jemand verwenden sollte time.time(), um die verstrichene Zeit in modernem Python zu messen (beeinflusst durch manuelle Änderungen, Drift, Schaltsekunden usw.). Diese Antwort unten muss höher sein, da diese Frage jetzt das beste Ergebnis in Google für die Messung der verstrichenen Zeit ist.
NPras
Sie können die Zeit auch mit dem cProfile-Profiler messen: docs.python.org/3/library/profile.html#module-cProfile stackoverflow.com/questions/582336/…
Anton Tarasenko
1
@NPras vergessen "moderne Python". Es war immer falsch zu benutzen time.time().
OrangeDog

Antworten:

514
start_time = time.time()
# your code
elapsed_time = time.time() - start_time

Sie können auch einen einfachen Dekorator schreiben, um die Messung der Ausführungszeit verschiedener Funktionen zu vereinfachen:

import time
from functools import wraps

PROF_DATA = {}

def profile(fn):
    @wraps(fn)
    def with_profiling(*args, **kwargs):
        start_time = time.time()

        ret = fn(*args, **kwargs)

        elapsed_time = time.time() - start_time

        if fn.__name__ not in PROF_DATA:
            PROF_DATA[fn.__name__] = [0, []]
        PROF_DATA[fn.__name__][0] += 1
        PROF_DATA[fn.__name__][1].append(elapsed_time)

        return ret

    return with_profiling

def print_prof_data():
    for fname, data in PROF_DATA.items():
        max_time = max(data[1])
        avg_time = sum(data[1]) / len(data[1])
        print "Function %s called %d times. " % (fname, data[0]),
        print 'Execution time max: %.3f, average: %.3f' % (max_time, avg_time)

def clear_prof_data():
    global PROF_DATA
    PROF_DATA = {}

Verwendungszweck:

@profile
def your_function(...):
    ...

Sie können mehrere Funktionen gleichzeitig profilieren. Um dann Messungen zu drucken, rufen Sie einfach print_prof_data () auf:

Vadim Shender
quelle
11
Sie können auch einen Blick auf Profilhooks pip install profilehooks und seine Homepage hier
werfen
11
Beachten Sie, dass man seit Python 3.3 wahrscheinlich time.monotonic()eher verwenden sollte, time.time()als Timeouts oder Dauern zu messen. docs.python.org/3/library/time.html#time.monotonic
Debilski
39
Erwähnenswert ist hier, dass die Maßeinheit für die verstrichene Zeit Sekunden beträgt.
Eric Kramer
4
@ EricKramer danke! Ein riesiges Haustier von mir, das Messungen erklärt, ohne die Maßeinheit zu definieren. Und als ein .NET-Typ, der zum ersten Mal seine Zehen in Python taucht, dachte ich automatisch "Millisekunden".
Adam Plocher
2
Funktioniert nicht, wenn (z. B.) die Systemuhr geändert wird und möglicherweise keine Auflösung von weniger als einer Sekunde hat. Richtige Antwort: stackoverflow.com/a/47637891/476716
OrangeDog
97

time.time() wird den Job machen.

import time

start = time.time()
# run your code
end = time.time()

elapsed = end - start

Vielleicht möchten Sie sich diese Frage ansehen , aber ich denke nicht, dass dies notwendig sein wird.

lalli
quelle
6
Ja, die Zeit ist in Sekunden
Eric Kramer
Sie sollten start in start_time ändern.
Zoran Pandovski
time.time()ist eine schlechte Idee, da die Systemuhr zurückgesetzt werden kann, wodurch Sie in der Zeit zurückgehen. time.monotonic()kümmert sich darum (monoton = es geht nur vorwärts). time.perf_counter()ist ebenfalls monoton, hat aber eine noch höhere Genauigkeit, daher wird dies für die Wanduhrzeit empfohlen.
xjcl
75

Für Benutzer, die eine bessere Formatierung wünschen,

import time
start_time = time.time()
# your script
elapsed_time = time.time() - start_time
time.strftime("%H:%M:%S", time.gmtime(elapsed_time))

wird 2 Sekunden lang ausgedruckt:

'00:00:02'

und für 7 Minuten eine Sekunde:

'00:07:01'

Beachten Sie, dass die minimale Zeiteinheit mit gmtime Sekunden beträgt. Wenn Sie Mikrosekunden benötigen, beachten Sie Folgendes:

import datetime
start = datetime.datetime.now()
# some code
end = datetime.datetime.now()
elapsed = end - start
print(elapsed)
# or
print(elapsed.seconds,":",elapsed.microseconds) 

Strftime- Dokumentation

Rutger Hofste
quelle
1
Vielen Dank für Ihre Antwort, die mich inspiriert. Ich werde e = time.time() - start_time ; print("%02d:%02d:%02d" % (e // 3600, (e % 3600 // 60), (e % 60 // 1)))diese Erträge fast gleich nutzen und die Situation abdecken, die mehr als 24 Stunden verstrichen ist.
Tora
@Tora Sie möchten möglicherweise "{}". Format () anstelle von% 02d für zukünftige Kompatibilitätsprobleme überprüfen.
Rutger Hofste
2
Vielen Dank! Jetzt gewöhne ich mich an den neuen. '{: 02d}: {: 02d}: {: 02d}'. Format (e // 3600, (e% 3600 // 60), e% 60)
Tora
können Sie time.monotonic()wie in den anderen Antworten verwenden?
Endolith
elapsed.secondsist falsch, wenn die Dauer länger als ein Tag ist. Sie wollen elapsed.total_seconds()belastbar sein
Ash Berlin-Taylor
51

Verwenden Sie für das beste Maß für die verstrichene Zeit (seit Python 3.3) time.perf_counter().

Gibt den Wert (in Sekundenbruchteilen) eines Leistungsindikators zurück, dh eine Uhr mit der höchsten verfügbaren Auflösung, um eine kurze Dauer zu messen. Es enthält die im Schlaf verstrichene Zeit und ist systemweit. Der Referenzpunkt des zurückgegebenen Werts ist undefiniert, sodass nur die Differenz zwischen den Ergebnissen aufeinanderfolgender Aufrufe gültig ist.

Bei Messungen in der Größenordnung von Stunden / Tagen ist Ihnen die Auflösung in Sekunden nicht wichtig. Verwenden Sie sie time.monotonic()stattdessen.

Gibt den Wert (in Sekundenbruchteilen) einer monotonen Uhr zurück, dh einer Uhr, die nicht rückwärts gehen kann. Die Uhr wird von Systemuhraktualisierungen nicht beeinflusst. Der Referenzpunkt des zurückgegebenen Werts ist undefiniert, sodass nur die Differenz zwischen den Ergebnissen aufeinanderfolgender Aufrufe gültig ist.

In vielen Implementierungen können diese tatsächlich dasselbe sein.

Vor 3.3 stecken Sie fest time.clock().

Geben Sie unter Unix die aktuelle Prozessorzeit als Gleitkommazahl in Sekunden zurück. Die Genauigkeit und tatsächlich die Definition der Bedeutung von "Prozessorzeit" hängt von der der gleichnamigen C-Funktion ab.

Unter Windows gibt diese Funktion die seit dem ersten Aufruf dieser Funktion verstrichenen Wanduhrsekunden als Gleitkommazahl zurück, basierend auf der Win32-Funktion QueryPerformanceCounter (). Die Auflösung ist normalerweise besser als eine Mikrosekunde.


Update für Python 3.7

Neu in Python 3.7 ist PEP 564 - Fügen Sie neue Zeitfunktionen mit einer Auflösung von Nanosekunden hinzu.

Durch diese Verwendung können Rundungs- und Gleitkommafehler weiter vermieden werden, insbesondere wenn Sie sehr kurze Zeiträume messen oder Ihre Anwendung (oder Ihr Windows-Computer) eine lange Laufzeit hat.

Die Auflösung beginnt perf_counter()nach etwa 100 Tagen zusammenzubrechen. So ist beispielsweise nach einem Jahr Betriebszeit das kürzeste Intervall (größer als 0), das gemessen werden kann, größer als zu Beginn.


Update für Python 3.8

time.clock ist jetzt weg.

OrangeDog
quelle
"In vielen Implementierungen können diese tatsächlich dasselbe sein." Auf meinem Linux Mint-PC scheinen time.monotonic () und time.perf_counter () identische Werte zurückzugeben.
xjcl
7

Für einen längeren Zeitraum.

import time
start_time = time.time()
...
e = int(time.time() - start_time)
print('{:02d}:{:02d}:{:02d}'.format(e // 3600, (e % 3600 // 60), e % 60))

würde drucken

00:03:15

wenn mehr als 24 Stunden

25:33:57

Das ist inspiriert von Rutger Hofstes Antwort. Danke Rutger!

Tora
quelle
6

Sie müssen die Zeit importieren und dann die Methode time.time () verwenden, um die aktuelle Zeit zu ermitteln.

import time

start_time=time.time() #taking current time as starting time

#here your code

elapsed_time=time.time()-start_time #again taking current time - starting time 
Nurul Akter Towhid
quelle
3

Eine weitere nette Art und Weise zu Zeit Dingen ist die Verwendung mit Python - Struktur.

with struct ruft automatisch die Methoden __enter__ und __exit__ auf , genau das, was wir brauchen, um die Dinge zeitlich zu steuern .

Lassen Sie uns eine Timer- Klasse erstellen .

from time import time

class Timer():
    def __init__(self, message):
        self.message = message
    def __enter__(self):
        self.start = time()
        return None  # could return anything, to be used like this: with Timer("Message") as value:
    def __exit__(self, type, value, traceback):
        elapsed_time = (time() - self.start) * 1000
        print(self.message.format(elapsed_time))

Dann kann man die Timer-Klasse folgendermaßen verwenden:

with Timer("Elapsed time to compute some prime numbers: {}ms"):
    primes = []
    for x in range(2, 500):
        if not any(x % p == 0 for p in primes):
            primes.append(x)
    print("Primes: {}".format(primes))

Das Ergebnis ist folgendes:

Primzahlen: [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499]

Verstrichene Zeit zur Berechnung einiger Primzahlen: 5.01704216003418ms

TM
quelle
2

Die Antwort von Vadim Shender ist großartig. Sie können auch einen einfacheren Dekorateur wie den folgenden verwenden:

import datetime
def calc_timing(original_function):                            
    def new_function(*args,**kwargs):                        
        start = datetime.datetime.now()                     
        x = original_function(*args,**kwargs)                
        elapsed = datetime.datetime.now()                      
        print("Elapsed Time = {0}".format(elapsed-start))     
        return x                                             
    return new_function()  

@calc_timing
def a_func(*variables):
    print("do something big!")
Mohammad
quelle
1

Bei der Programmierung gibt es zwei Möglichkeiten, die Zeit mit unterschiedlichen Ergebnissen zu messen :

>>> print(time.process_time()); time.sleep(10); print(time.process_time())
0.11751394000000001
0.11764988400000001  # took  0 seconds and a bit
>>> print(time.perf_counter()); time.sleep(10); print(time.perf_counter())
3972.465770326
3982.468109075       # took 10 seconds and a bit
  • Prozessorzeit : Dies ist die Zeit, die dieser bestimmte Prozess aktiv auf der CPU ausführt. Der Ruhezustand, das Warten auf eine Webanforderung oder die Zeit, in der nur andere Prozesse ausgeführt werden, tragen nicht dazu bei.

    • Verwenden time.process_time()
  • Wanduhrzeit : Dies bezieht sich darauf, wie viel Zeit "auf einer an der Wand hängenden Uhr" vergangen ist, dh außerhalb der Echtzeit.

    • Verwenden time.perf_counter()

      • time.time() Misst auch die Wanduhrzeit, kann aber zurückgesetzt werden, sodass Sie in der Zeit zurückgehen können
      • time.monotonic() kann nicht zurückgesetzt werden (monoton = geht nur vorwärts), hat aber eine geringere Genauigkeit als time.perf_counter()
xjcl
quelle
0

Hier ist ein Update von Vadim Shenders cleverem Code mit tabellarischer Ausgabe:

import collections
import time
from functools import wraps

PROF_DATA = collections.defaultdict(list)

def profile(fn):
    @wraps(fn)
    def with_profiling(*args, **kwargs):
        start_time = time.time()
        ret = fn(*args, **kwargs)
        elapsed_time = time.time() - start_time
        PROF_DATA[fn.__name__].append(elapsed_time)
        return ret
    return with_profiling

Metrics = collections.namedtuple("Metrics", "sum_time num_calls min_time max_time avg_time fname")

def print_profile_data():
    results = []
    for fname, elapsed_times in PROF_DATA.items():
        num_calls = len(elapsed_times)
        min_time = min(elapsed_times)
        max_time = max(elapsed_times)
        sum_time = sum(elapsed_times)
        avg_time = sum_time / num_calls
        metrics = Metrics(sum_time, num_calls, min_time, max_time, avg_time, fname)
        results.append(metrics)
    total_time = sum([m.sum_time for m in results])
    print("\t".join(["Percent", "Sum", "Calls", "Min", "Max", "Mean", "Function"]))
    for m in sorted(results, reverse=True):
        print("%.1f\t%.3f\t%d\t%.3f\t%.3f\t%.3f\t%s" % (100 * m.sum_time / total_time, m.sum_time, m.num_calls, m.min_time, m.max_time, m.avg_time, m.fname))
    print("%.3f Total Time" % total_time)
Steve
quelle