Pomiar upływu czasu za pomocą modułu czasu

337

Czy w module Python w Pythonie można mierzyć upływ czasu? Jeśli tak, jak to zrobić?

Muszę to zrobić, aby kursor znajdował się w widżecie przez określony czas, a więc zdarzenie.

prostokąt
źródło
3
Uwaga: każda użyta odpowiedź time.time()jest niepoprawna. Najprostszym przykładem jest zmiana czasu systemowego w okresie pomiaru.
OrangeDog,
W przypadku twojego pierwotnego pytania dotyczącego odpalenia zdarzenia, jeśli kursor pozostaje przez pewien czas w widżecie, docs.python.org/3/library/threading.html zapewnia wszystko, czego potrzebujesz. Jednym z rozwiązań może być wielowątkowość i zmienna warunkowa z limitem czasu. Twoja sytuacja jest jednak obecnie niejasna.
Tora,
2
Nie ma powodu, dla którego ktoś powinien używać time.time()do pomiaru czasu, jaki upłynął we współczesnym pythonie (na który wpływ mają ręczne zmiany, dryf, sekundy przestępne itp.). Poniższa odpowiedź musi być wyższa, biorąc pod uwagę, że to pytanie jest obecnie najlepszym wynikiem w Google pod względem pomiaru upływu czasu.
NPras
Możesz także mierzyć czas za pomocą profilera cProfile: docs.python.org/3/library/profile.html#module-cProfile stackoverflow.com/questions/582336/...
Anton Tarasenko
1
@NPras zapomina „nowoczesny python”. Zawsze był niewłaściwy w użyciu time.time().
OrangeDog

Odpowiedzi:

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

Możesz także napisać prosty dekorator, aby uprościć pomiar czasu wykonywania różnych funkcji:

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 = {}

Stosowanie:

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

Możesz profilować więcej niż jedną funkcję jednocześnie. Następnie, aby wydrukować pomiary, po prostu wywołaj print_prof_data ():

Vadim Shender
źródło
11
Możesz także zobaczyć haczyki profilowe pip install profilehooks i ich stronę główną tutaj
pjama,
11
Zauważ, że od wersji Python 3.3 należy time.monotonic()raczej używać niż do time.time()pomiaru limitów czasu lub czasów trwania. docs.python.org/3/library/time.html#time.monotonic
Debilski
39
Warto dodać / zauważyć, że jednostką miary dla upływu czasu będą sekundy.
Eric Kramer
4
@EricKramer dziękuję! moje ogromne zwierzę domowe, wyjaśniające pomiary bez określania jednostki miary. I jako gość .NET po raz pierwszy zanurzający palce w Pythonie, automatycznie pomyślałem „milisekundy”.
Adam Plocher
2
Nie działa, jeśli (np.) Zegar systemowy został zmieniony i może nie mieć rozdzielczości drugiej sekundy. Prawidłowa odpowiedź: stackoverflow.com/a/47637891/476716
OrangeDog
97

time.time() wykona robotę.

import time

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

elapsed = end - start

Możesz przyjrzeć się temu pytaniu, ale nie sądzę, aby było to konieczne.

lalli
źródło
6
Tak, czas jest w sekundach
Eric Kramer
Powinieneś zmienić początek na start_time.
Zoran Pandovski
time.time()to zły pomysł, ponieważ zegar systemowy można zresetować, co spowoduje cofnięcie się w czasie. time.monotonic()dba o to (monotoniczny = idzie tylko do przodu). time.perf_counter()jest również monotoniczny, ale ma jeszcze wyższą dokładność, dlatego jest to zalecane w przypadku zegara ściennego.
xjcl
76

Dla użytkowników, którzy chcą lepszego formatowania,

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

wydrukuje przez 2 sekundy:

'00:00:02'

i przez 7 minut jedna sekunda:

'00:07:01'

zwróć uwagę, że minimalna jednostka czasu z gmtime to sekundy. Jeśli potrzebujesz mikrosekund, rozważ następujące kwestie:

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

dokumentacja strftime

Rutger Hofste
źródło
1
Dziękuję za odpowiedź, która mnie inspiruje. Mam zamiar użyć, e = time.time() - start_time ; print("%02d:%02d:%02d" % (e // 3600, (e % 3600 // 60), (e % 60 // 1)))że plony są prawie takie same, a także obejmują sytuację, która upłynęła ponad 24 godziny.
Tora
@Tora możesz wypróbować format „{}”. () Zamiast% 02d w celu uzyskania informacji na temat przyszłych problemów ze zgodnością.
Rutger Hofste
2
Dziękuję Ci! Teraz przyzwyczajam się do nowego. „{: 02d}: {: 02d}: {: 02d}”. Format (e // 3600, (e% 3600 // 60), e% 60)
Tora
czy możesz użyć time.monotonic()jak w innych odpowiedziach?
endolith,
elapsed.secondsbędzie niepoprawna, jeśli czas trwania będzie dłuższy niż jeden dzień. Chcesz elapsed.total_seconds()być odporny
Ash Berlin-Taylor
51

Aby uzyskać najlepszą miarę upływu czasu (od Python 3.3), użyj time.perf_counter().

Zwraca wartość (w ułamkach sekund) licznika wydajności, tj. Zegara o najwyższej dostępnej rozdzielczości do pomiaru krótkotrwałego. Obejmuje czas, który upłynął podczas snu i obejmuje cały system. Punkt odniesienia zwracanej wartości jest niezdefiniowany, dlatego ważna jest tylko różnica między wynikami kolejnych wywołań.

W przypadku pomiarów rzędu godzin / dni nie przejmujesz się rozdzielczością poniżej sekundy, więc użyj time.monotonic()zamiast tego.

Zwraca wartość (w ułamkach sekund) zegara monotonicznego, tj. Zegara, który nie może się cofnąć. Aktualizacje zegara systemowego nie mają wpływu na zegar. Punkt odniesienia zwracanej wartości jest niezdefiniowany, dlatego ważna jest tylko różnica między wynikami kolejnych wywołań.

W wielu implementacjach mogą to być faktycznie to samo.

Przed 3.3, utkniesz z time.clock().

W systemie Unix zwróć bieżący czas procesora jako liczbę zmiennoprzecinkową wyrażoną w sekundach. Precyzja, a właściwie sama definicja znaczenia „czasu procesora”, zależy od funkcji C o tej samej nazwie.

W systemie Windows funkcja ta zwraca sekundy zegara, które upłynęły od pierwszego wywołania tej funkcji, jako liczbę zmiennoprzecinkową, na podstawie funkcji Win32 QueryPerformanceCounter (). Rozdzielczość jest zwykle lepsza niż jedna mikrosekunda.


Aktualizacja dla Python 3.7

Nowością w Python 3.7 jest PEP 564 - Dodaj nowe funkcje czasowe o rozdzielczości nanosekundowej.

Korzystanie z nich może dodatkowo wyeliminować błędy zaokrąglania i zmiennoprzecinkowe, szczególnie jeśli mierzysz bardzo krótkie okresy lub aplikacja (lub komputer z systemem Windows) działa długo.

Rozdzielczość zaczyna się załamywać perf_counter()po około 100 dniach. Na przykład po roku nieprzerwanej pracy najkrótszy przedział (większy niż 0), który można zmierzyć, będzie większy niż w momencie rozpoczęcia.


Aktualizacja dla Python 3.8

time.clock już nie ma.

OrangeDog
źródło
„W wielu implementacjach mogą to być w rzeczywistości to samo”. To prawda, że ​​na moim Linux Mint PC time.monotonic () i time.perf_counter () zwracają identyczne wartości.
xjcl
7

Na dłuższy okres.

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

wydrukuje

00:03:15

jeśli więcej niż 24 godziny

25:33:57

Jest to inspirowane odpowiedzią Rutger Hofste. Dziękuję Rutger!

Tora
źródło
6

Musisz zaimportować czas, a następnie użyć metody time.time (), aby poznać aktualny czas.

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
źródło
3

Innym fajnym sposobem na określenie czasu jest użycie struktury z pythonem.

ze strukturą automatycznie wywołuje metody __enter__ i __exit__ , co jest dokładnie tym, czego potrzebujemy do pomiaru czasu.

Stwórzmy timera klasę.

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

Następnie można użyć klasy Timer w następujący sposób:

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

Wynik jest następujący:

Liczby pierwsze: [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]

Upłynął czas obliczenia niektórych liczb pierwszych: 5.01704216003418ms

TM
źródło
2

Odpowiedź Vadima Shendera jest świetna. Możesz także użyć prostszego dekoratora, takiego jak poniżej:

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
źródło
1

W programowaniu istnieją 2 główne sposoby pomiaru czasu , z różnymi wynikami:

>>> 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
  • Czas procesora : tyle czasu ten konkretny proces spędza aktywnie wykonywany na procesorze. Uśpienie, oczekiwanie na żądanie sieciowe lub czas, w którym wykonywane są tylko inne procesy, nie przyczyni się do tego.

    • Posługiwać się time.process_time()
  • Czas naścienny : Odnosi się do tego, ile czasu minęło „na zegarze wiszącym na ścianie”, tj. Poza czasem rzeczywistym.

    • Posługiwać się time.perf_counter()

      • time.time() mierzy również czas naścienny, ale można go zresetować, aby można było cofnąć się w czasie
      • time.monotonic() nie można go zresetować (monotoniczny = tylko idzie do przodu), ale ma mniejszą dokładność niż time.perf_counter()
xjcl
źródło
0

Oto aktualizacja sprytnego kodu Vadima Shendera z tabelarycznym wynikiem:

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
źródło