2011-09-14 3 views
46

C'è un modo semplice/modulo per corretto misurare il tempo trascorso in python? So che posso semplicemente chiamare lo time.time() due volte e fare la differenza, ma ciò produrrà risultati errati se l'ora del sistema viene modificata. Certo, ciò non accade molto spesso, ma indica che sto misurando la cosa sbagliata.Misurazione del tempo trascorso in python

Utilizzare time.time() per misurare le durate è incredibilmente rotonda quando ci pensate. Prendi la differenza tra due misurazioni del tempo assoluto che sono a loro volta costruite da misure di durata (eseguite da timer) e tempi assoluti noti (impostati manualmente o tramite ntp), che non ti interessano affatto.

Quindi, c'è un modo per interrogare direttamente questo "tempo del timer"? Immagino che possa essere rappresentato come un valore millisecondo o microsecondo che non ha una rappresentazione assoluta significativa (e quindi non ha bisogno di essere regolato con il tempo di sistema). Guardando un po 'sembra che questo sia esattamente ciò che fa System.nanoTime() in Java, ma non ho trovato una funzione Python corrispondente, anche se (hardware-tecnicamente) dovrebbe essere più facile da fornire rispetto a time.time().

Modifica: Per evitare confusione e risolvere le risposte di seguito: Non si tratta di modifiche all'ora legale e non voglio nemmeno il tempo di CPU: voglio il tempo fisico trascorso. Non ha bisogno di essere a grana fine e nemmeno particolarmente accurato. Semplicemente non dovrebbe darmi durate negative o durate diverse di diversi ordini di grandezza (oltre la granularità), solo perché qualcuno ha deciso di impostare l'orologio di sistema su un valore diverso. Ecco ciò che i documenti dicono di Python 'time.time()':

"While this function normally returns non-decreasing values, it can return a lower value than a previous call if the system clock has been set back between the two calls"

Questo è esattamente quello che voglio evitare, dal momento che può portare a cose strane come valori negativi nei calcoli di tempo. Posso aggirare il problema al momento, ma credo sia una buona idea imparare a utilizzare le soluzioni appropriate laddove possibile, dal momento che i kludges torneranno a morderti un giorno.

Edit2: Alcune ricerche mostrano che è possibile ottenere una misurazione indipendente dall'orario del sistema come si desidera in Windows utilizzando GetTickCount64(), in Linux è possibile ottenerlo nel valore restituito di times(). Tuttavia, non riesco ancora a trovare un modulo che fornisca questa funzionalità in Python.

+2

Se si desidera eseguire il benchmark di qualcosa, è necessario utilizzare 'timeit'. – delnan

+1

correlati: [Come ottengo durata temporale monotona in python?] (Http://stackoverflow.com/questions/1205722/how-do-i-get-monotonic-time-durations-in-python) – jfs

risposta

10

Quello che sembra essere uno monotonic timer. A monotonic time reference non salta o torna indietro.

Ci sono stati diversi tentativi di implementare un orologio monotomico multipiattaforma per Python in base al riferimento del sistema operativo. (Windows, POSIX e BSD sono abbastanza diversi) Vedi le discussioni e alcuni dei tentativi in ​​tempo monotonico in this SO post.

Principalmente, si può semplicemente utilizzare os.times():

os.times()

ritorno 5-upla di numeri in virgola indicano accumulato (processore o altro) volte galleggiante, in secondi. Gli articoli sono: tempo utente, ora di sistema, ora utente bambini, ora di sistema per bambini, e tempo reale trascorso da un punto fisso nel passato, in quell'ordine. Vedere i tempi di pagina manuale Unix (2) o la documentazione relativa all'API della piattaforma Windows corrispondente. Su Windows, solo i primi due elementi sono riempiti con , gli altri sono zero.

Disponibilità: Unix, Windows

Ma ciò non riempire il tempo reale trascorso necessario (la quinta tupla) su Windows.

Se è necessario il supporto di Windows, prendere in considerazione ctypes ed è possibile chiamare direttamente GetTickCount64(), come è stato fatto in this recipe.

+1

Mi chiedo perché nessuno abbia proposto di aggiungere il quinto valore della tupla a os.times su Windows? Sembra che dovrebbe essere possibile, in quanto il punto di riferimento non è specificato. –

+0

@Mark Ransome: Non essendo un ragazzo Winoze, ma forse perché qualcosa come 'GetTickCount64()' o la versione 32 dello stesso non è nell'API di base di Windows che è assunta nella linea di base per cPython? cioè, supporto legacy su quella piattaforma? Non so altrimenti Il riferimento temporale monotonico è una caratteristica utile. –

24

Per misurare il tempo di CPU trascorso, consultare time.clock(). Questo è l'equivalente del campo ora utente times() di Linux.

Per il benchmarking, utilizzare timeit.

Il datetime module, which is part of Python 2.3+, ha anche un tempo di microsecondi se supportato dalla piattaforma.

Esempio:

>>> import datetime as dt 
>>> n1=dt.datetime.now() 
>>> n2=dt.datetime.now() 
>>> (n2-n1).microseconds 
678521 
>>> (n2.microsecond-n1.microsecond)/1e6 
0.678521 
ie, it took me .678521 seconds to type the second n2= line -- slow 
>>> n1.resolution 
datetime.timedelta(0, 0, 1) 
1/1e6 resolution is claimed. 

Se siete preoccupati per i cambiamenti di tempo di sistema (da DS -> ST) basta controllare l'oggetto restituito dal datetime.Presumably, l'ora di sistema potrebbe avere un piccolo aggiustamento da un riferimento NTP regolazione. This should be slewed e le correzioni sono applied gradually, ma i beat di sincronizzazione ntp possono avere un effetto con riferimenti temporali molto piccoli (millisecondi o microsecondi).

È anche possibile fare riferimento a Alex Martelli's C function se si desidera qualcosa di tale risoluzione. Non andrei troppo lontano per reinventare la ruota. Il tempo preciso è di base e il sistema operativo più moderno fa un buon lavoro.

Modifica

In base alle vostre precisazioni, suona come avete bisogno di un semplice controllo lato se l'orologio del sistema è cambiato. Basta confrontare ad un amichevole, server NTP locale:

import socket 
import struct 
import time 

ntp="pool.ntp.org" # or whatever ntp server you have handy 

client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 
data = '\x1b' + 47 * '\0' 
client.sendto(data, (ntp, 123)) 
data, address = client.recvfrom(1024) 
if data: 
    print 'Response received from:', address 
    t = struct.unpack('!12I', data)[10] 
    t -= 2208988800L #seconds since Epoch 
    print '\tTime=%s' % time.ctime(t) 

NTP è esatto millisecondi su Internet e ha una risoluzione rappresentazione della risoluzione di 2-32 secondi (233 picosecondi). Dovrebbe essere abbastanza buono?

Essere consapevoli del fatto che la struttura di dati bit NTP 64 will overflow in 2036 and every 136 years thereafter - se si vuole veramente una soluzione robusta, migliore controllo per troppo pieno ...

+1

+1 per le informazioni di rotazione, che attenuano il problema. Tuttavia, non cerco una maggiore granularità. In effetti, nella mia attuale applicazione, i secondi andrebbero bene. – Medo42

+2

Non penso che una query del server NTP sia una soluzione elegante. Dopo tutto, c'è un hardware dedicato per misurare ciò che voglio costruire in praticamente tutti i PC, e può essere interrogato dalle funzioni di sistema su Windows e Linux - guarda la mia nuova modifica qui sopra. – Medo42

+0

@ Medo42: non è necessario eseguire la chiamata ntp ogni istanza del timer; solo se 'time.time()' ha restituito un numero negativo o qualcosa di inaspettato. [Pyson's] (http://stackoverflow.com/questions/7421617/measuring-elapsed-time-in-python/7423817#7423817) metodo di confronto con 'time.clock()' ha valore. Potresti usare qualcosa del genere per innescare quando fare un confronto con una fonte esterna. Personalmente, il tempo del sistema operativo è abbastanza buono per i tempi + millisecondo per me. L'uso di un timer HW ha i suoi problemi di accuratezza. La wiki della community – dawg

4
>>> import datetime 
>>> t1=datetime.datetime.utcnow() 
>>> t2=datetime.datetime.utcnow() 
>>> t2-t1 
datetime.timedelta(0, 8, 600000) 

Utilizzando UTC evita quei periodi imbarazzanti quando l'orologio si sposta a causa di ora legale.

Per quanto riguarda l'utilizzo di un metodo alternativo anziché sottrarre due orologi, tenere presente che il sistema operativo contiene effettivamente un orologio che viene inizializzato da un orologio hardware nel PC. Le moderne implementazioni del sistema operativo manterranno anche quell'orologio sincronizzato con alcune fonti ufficiali in modo che non si spostino. Questo è molto più accurato di qualsiasi timer a intervalli che il PC potrebbe eseguire.

+1

Più preciso - sì, a lungo termine. Questo tempo di orologio può comportarsi in modo strano sebbene nell'istante in cui viene regolato (a meno che la regolazione non sia stata modificata, come descritto nella risposta di Drewk).Non ho bisogno di alta precisione per tempi lunghi, ma voglio misurazioni affidabili a breve termine che non diano intervalli negativi o troppo grandi solo perché qualcuno ha deciso di cambiare manualmente l'orario del sistema - cosa che succede a volte. – Medo42

2

Le funzioni di esempio si Stato nella tua modifica sono due cose completamente diverse: tempi

  1. Linux processo times() ritorni in millisecondi di CPU. L'equivalente di Python è time.clock() o os.times().
  2. Windows GetTickCount64() restituisce tempo di attività del sistema.

Anche se due funzioni diverse, sia (potenzialmente) potrebbero essere utilizzati per rivelare un orologio di sistema che ha avuto un "rutto" con questi metodi:

Primo:

si poteva prendere sia un tempo di sistema con time.time() e tempo CPU con time.clock(). Poiché il tempo di orologio a muro sarà SEMPRE maggiore o uguale al tempo della CPU, eliminare le misurazioni in cui l'intervallo tra le due letture time.time() è inferiore alle letture di controllo accoppiate time.clock().

Esempio:

t1=time.time() 
t1check=time.clock() 

# your timed event...  

t2=time.time() 
t2check=time.clock() 

if t2-t1 < t2check - t1check: 
    print "Things are rotten in Denmark" 
    # discard that sample 
else: 
    # do what you do with t2 - t1... 

Secondo:

Ottenere operatività del sistema è anche promettente, se siete preoccupati per l'orologio del sistema, dal momento che un reset utente non azzera il conteggio di uptime segno di spunta nella maggior parte dei casi . (che io sappia ...)

Ora la domanda più difficile: ottenere il tempo di funzionamento del sistema in modo indipendente dalla piattaforma - in particolare senza generare un nuovo guscio - con la precisione al secondo. Hmmm ...

Probabilmente la migliore scommessa è psutil. Browsing the source, usano uptime = GetTickCount()/1000.00f; per Windows e sysctl "kern.boottime" per BSD/OS X, ecc. Sfortunatamente, si tratta di una risoluzione di 1 secondo.

+0

Anch'io ero confuso su times() all'inizio, ma leggevo il tuo manuale collegato (in particolare la parte che dice "Valore di ritorno"). La funzione può essere usata per trovare i tempi di processo che sono inseriti in una struttura fornita, ma * restituisce * un orologio di sistema indipendente dalla misura del tempo. – Medo42

+0

@ Medo42: sei corretto, mio ​​cattivo. –

+0

È vero che l'ora dell'orologio da parete sarà sempre maggiore del tempo della CPU? Credo che questo sia solo il caso dei sistemi single core. – Alex

2
from datetime import datetime 
start = datetime.now() 
print 'hello' 
end = datetime.now() 
delta = end-start 
print type(delta) 
<type 'datetime.timedelta'> 
import datetime 
help(datetime.timedelta) 
...elapsed seconds and microseconds...