Quanto è accurato time.sleep () di python?


95

Posso dargli numeri in virgola mobile, come

time.sleep(0.5)

ma quanto è preciso? Se lo do

time.sleep(0.05)

dormirà davvero per circa 50 ms?

Risposte:


78

La precisione della funzione time.sleep dipende dalla precisione del sonno del sistema operativo sottostante. Per i sistemi operativi non in tempo reale come un Windows stock, l'intervallo più piccolo per cui puoi dormire è di circa 10-13 ms. Ho visto sleep accurati entro diversi millisecondi da quel tempo quando sono superiori al minimo di 10-13 ms.

Aggiornamento: come menzionato nei documenti citati di seguito, è comune fare il sonno in un ciclo che si assicurerà di tornare a dormire se ti sveglia presto.

Dovrei anche menzionare che se stai usando Ubuntu puoi provare uno pseudo kernel in tempo reale (con il set di patch RT_PREEMPT) installando il pacchetto del kernel rt (almeno in Ubuntu 10.04 LTS).

EDIT: I kernel Linux non in tempo reale di correzione hanno un intervallo di sospensione minimo molto più vicino a 1 ms quindi 10 ms, ma varia in modo non deterministico.


8
In realtà, i kernel Linux sono passati di default a un tick rate più alto per un bel po 'di tempo, quindi il sonno "minimo" è molto più vicino a 1ms che a 10ms. Non è garantito: altre attività di sistema possono impedire al kernel di pianificare il processo non appena lo desideri, anche senza conflitti di CPU. Questo è ciò che i kernel in tempo reale stanno cercando di riparare, credo. Ma, a meno che tu non abbia davvero bisogno di un comportamento in tempo reale, il semplice utilizzo di un tick rate elevato (impostazione HZ del kernel) ti consentirà di dormire non garantiti ma ad alta risoluzione in Linux senza usare nulla di speciale.
Glenn Maynard

1
Sì, hai ragione, ho provato con Linux 2.6.24-24 e sono riuscito ad avvicinarmi abbastanza a velocità di aggiornamento di 1000 Hz. In quel momento stavo eseguendo il codice anche su Mac e Windows, quindi probabilmente mi sono confuso. So che Windows XP ha almeno una frequenza di tick di circa 10 ms.
Joseph Lisee,

Su Windows 8 ottengo poco meno di 2 ms
markmnl

2
Inoltre la precisione non dipende solo dal sistema operativo, ma da ciò che il sistema operativo sta facendo sia su Windows che su Linux se sono impegnati a fare qualcosa di più importante sleep()dai documenti "il tempo di sospensione potrebbe essere più lungo di quanto richiesto da una quantità arbitraria a causa della pianificazione di altra attività nel sistema ".
markmnl

55

Le persone hanno ragione sulle differenze tra sistemi operativi e kernel, ma non vedo alcuna granularità in Ubuntu e vedo una granularità di 1 ms in MS7. Suggerendo un'implementazione diversa di time.sleep, non solo una diversa frequenza di tick. Un'ispezione più attenta suggerisce una granularità di 1μs in Ubuntu, a proposito, ma ciò è dovuto alla funzione time.time che uso per misurare la precisione. Comportamento time.sleep tipico di Linux e Windows in Python


6
È interessante come Linux abbia scelto di dormire sempre un po 'più a lungo di quanto richiesto, mentre Microsoft ha scelto l'approccio opposto.
jleahy

2
@jleahy - l'approccio linux ha senso per me: sleep è davvero un rilascio della priorità di esecuzione per un periodo di tempo dopo il quale ti sottometti ancora una volta alla volontà dello scheduler (che può o meno programmarti per l'esecuzione immediatamente) .
underrun

2
come hai ottenuto i risultati? Potresti fornire il codice sorgente? Il grafico sembra un artefatto dell'utilizzo di timer diversi per misurare il tempo e il sonno (in linea di principio, potresti persino utilizzare la deriva tra i timer come fonte di casualità ).
jfs

1
@JF Sebastian - La funzione che ho usato è in socsci.ru.nl/wilberth/computer/sleepAccuracy.html . Il terzo grafico mostra un effetto simile a quello che vedi, ma di solo 1 ‰.
Wilbert,

1
@JF Sebastian Uso time.clock () su Windows
Wilbert

26

Dalla documentazione :

D'altra parte, la precisione di time()ed sleep()è migliore dei loro equivalenti Unix: i tempi sono espressi come numeri in virgola mobile, time()restituisce il tempo più accurato disponibile (utilizzando Unix gettimeofday dove disponibile) e sleep()accetterà un tempo con una frazione diversa da zero ( selectviene utilizzato Unix per implementarlo, se disponibile).

E più specificamente rispetto a sleep():

Sospendi l'esecuzione per il numero di secondi specificato. L'argomento può essere un numero in virgola mobile per indicare un tempo di sospensione più preciso. Il tempo di sospensione effettivo può essere inferiore a quello richiesto perché qualsiasi segnale catturato terminerà la sleep()successiva esecuzione della routine di cattura di quel segnale. Inoltre, il tempo di sospensione può essere più lungo di quanto richiesto da un importo arbitrario a causa della programmazione di altre attività nel sistema.


1
Qualcuno può spiegare il "perché qualsiasi segnale catturato terminerà lo sleep () dopo l'esecuzione della routine di cattura di quel segnale"? A quali segnali si riferisce? Grazie!
Diego Herranz

1
I segnali sono come le notifiche che il sistema operativo gestisce ( en.wikipedia.org/wiki/Unix_signal ), significa che se il sistema operativo riceve un segnale, sleep () termina dopo aver trattato quel segnale.
ArianJM

24

Ecco il mio seguito alla risposta di Wilbert: lo stesso per Mac OS X Yosemite, dal momento che non è stato ancora menzionato molto.Comportamento durante il sonno di Mac OS X Yosemite

Sembra che la maggior parte delle volte dorma circa 1,25 volte il tempo richiesto e talvolta dorma tra 1 e 1,25 volte il tempo richiesto. Non dorme quasi mai (~ due volte su 1000 campioni) per un tempo significativamente maggiore di 1,25 volte il tempo richiesto.

Inoltre (non mostrato esplicitamente) la relazione 1,25 sembra reggere abbastanza bene fino a quando non si scende al di sotto di circa 0,2 ms, dopodiché inizia a diventare un po 'sfocata. Inoltre, il tempo effettivo sembra stabilizzarsi a circa 5 ms in più rispetto a quanto richiesto dopo che la quantità di tempo richiesta supera i 20 ms.

Ancora una volta, sembra essere un'implementazione completamente diversa sleep()in OS X rispetto a Windows o qualsiasi altro kernel Linux che Wilbert stesse usando.


Potresti caricare il codice sorgente per il benchmark su github / bitbucket?
jfs

3
Ho provato che sulla mia macchina. Il risultato è simile alla risposta di @ Wilbert .
jfs

Immagino che il sonno stesso sia accurato, ma la pianificazione di Mac OS X non è abbastanza precisa da fornire una CPU abbastanza veloce da ritardare la riattivazione dalla sospensione. Se l'ora esatta del risveglio è importante, sembra che il sonno dovrebbe essere impostato a 0,75 volte quello effettivamente richiesto e controllare l'ora dopo il risveglio e dormire ripetutamente sempre meno alla volta fino all'ora corretta.
Mikko Rantalainen

16

Perché non scopri:

from datetime import datetime
import time

def check_sleep(amount):
    start = datetime.now()
    time.sleep(amount)
    end = datetime.now()
    delta = end-start
    return delta.seconds + delta.microseconds/1000000.

error = sum(abs(check_sleep(0.050)-0.050) for i in xrange(100))*10
print "Average error is %0.2fms" % error

Per la cronaca, ottengo circa 0,1 ms di errore sul mio HTPC e 2 ms sul mio laptop, entrambe le macchine Linux.


10
I test empirici ti daranno una visione molto ristretta. Ci sono molti kernel, sistemi operativi e configurazioni del kernel che influiscono su questo. I kernel Linux meno recenti impostano per impostazione predefinita una frequenza di tick inferiore, che si traduce in una maggiore granularità. Nell'implementazione Unix, un segnale esterno durante la sospensione lo annullerà in qualsiasi momento e altre implementazioni potrebbero avere interruzioni simili.
Glenn Maynard

6
Ovviamente l'osservazione empirica non è trasferibile. A parte i sistemi operativi e i kernel, ci sono molti problemi temporanei che influiscono su questo. Se sono necessarie garanzie rigide in tempo reale, è necessario prendere in considerazione l'intero design del sistema, dall'hardware in su. Ho appena trovato i risultati rilevanti considerando le affermazioni che 10ms è l'accuratezza minima. Non sono a casa nel mondo Windows, ma la maggior parte delle distribuzioni Linux ha eseguito kernel tickless da un po 'di tempo. Con i multicore ora prevalenti è molto probabile che venga programmato molto vicino al timeout.
Ants Aasma

4

Una piccola correzione, molte persone affermano che il sonno può essere interrotto presto da un segnale. Nei documenti 3.6 si dice,

Modificato nella versione 3.5: la funzione ora dorme almeno secondi anche se il sonno viene interrotto da un segnale, tranne se il gestore del segnale solleva un'eccezione (vedere PEP 475 per la motivazione).


3

Non puoi davvero garantire nulla su sleep (), tranne che farà del suo meglio per dormire finché glielo dici (i segnali possono uccidere il tuo sonno prima che il tempo sia scaduto, e molte più cose possono farlo funzionare lungo).

Sicuramente il minimo che puoi ottenere su un sistema operativo desktop standard sarà di circa 16 ms (granularità del timer più tempo per il cambio di contesto), ma è probabile che la deviazione% dall'argomento fornito sarà significativa quando stai provando dormire per 10 secondi di millisecondi.

Segnali, altri thread che mantengono il GIL, divertimento nella pianificazione del kernel, aumento della velocità del processore, ecc.


3
La documentazione dice diversamente:> Il tempo di sospensione effettivo potrebbe essere inferiore a quello richiesto perché qualsiasi segnale catturato terminerà lo sleep () dopo l'esecuzione della routine di cattura di quel segnale.
Glenn Maynard

Ah giusto punto, corretto il post, anche se dormire più a lungo () è molto più probabile di quelli più brevi.
Nick Bastin

1
Due anni e mezzo dopo ... la documentazione si trova ancora. Su Windows, i segnali non interromperanno lo sleep (). Testato su Python 3.2, WinXP SP3.
Dave

Sì, ma i segnali che anticipano il sonno sono insoliti, ad esempio KILL, la documentazione dice anche: "Inoltre, il tempo di sospensione potrebbe essere più lungo di quanto richiesto da una quantità arbitraria a causa della programmazione di altre attività nel sistema." che è più tipico.
markmnl

1
Singnals and Windows è semplicemente stupido. Su Windows Python time.sleep () attende su un ConsoleEvent per acquisire cose come Ctrl-C.
schlenk

1

se hai bisogno di maggiore precisione o di tempi di sonno più bassi, considera di crearne uno tuo:

import time

def sleep(duration, get_now=time.perf_counter):
    now = get_now()
    end = now + duration
    while now < end:
        now = get_now()


0
def start(self):
    sec_arg = 10.0
    cptr = 0
    time_start = time.time()
    time_init = time.time()
    while True:
        cptr += 1
        time_start = time.time()
        time.sleep(((time_init + (sec_arg * cptr)) - time_start ))

        # AND YOUR CODE .......
        t00 = threading.Thread(name='thread_request', target=self.send_request, args=([]))
        t00.start()

Non utilizzare una variabile per passare l'argomento di sleep (), devi inserire il calcolo direttamente in sleep ()


E il ritorno del mio terminale

1 ───── 17: 20: 16.891 ───────────────────

2 ───── 17: 20: 18.891 ────────────────────

3 ───── 17: 20: 20.891 ────────────────────

4 ───── 17: 20: 22.891 ───────────────────

5 ───── 17: 20: 24.891 ───────────────────

....

689 ─── 17: 43: 12.891 ─────────────────────

690 ─── 17: 43: 14.890 ────────────────────

691 ─── 17: 43: 16.891 ─────────────────────

692 ─── 17: 43: 18.890 ─────────────────────

693 ─── 17: 43: 20.891 ─────────────────────

...

727 ─── 17: 44: 28.891 ─────────────────────

728 ─── 17: 44: 30.891 ─────────────────────

729 ─── 17: 44: 32.891 ─────────────────────

730 ─── 17: 44: 34.890 ─────────────────────

731 ─── 17: 44: 36.891 ─────────────────────

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.