¿Qué tan exacto es el time.sleep () de Python?

95

Puedo darle números de punto flotante, como

time.sleep(0.5)

pero ¿qué tan exacto es? Si lo doy

time.sleep(0.05)

¿Realmente dormirá unos 50 ms?

Claudiu
fuente

Respuestas:

78

La precisión de la función time.sleep depende de la precisión del sueño del sistema operativo subyacente. Para sistemas operativos que no son en tiempo real, como Windows estándar, el intervalo más pequeño que puede dormir es de aproximadamente 10-13 ms. He visto dormidos precisos dentro de varios milisegundos de ese tiempo cuando está por encima del mínimo de 10-13 ms.

Actualización: como se menciona en los documentos que se citan a continuación, es común dormir en un bucle que se asegurará de volver a dormir si lo despierta temprano.

También debo mencionar que si está ejecutando Ubuntu, puede probar un kernel pseudo en tiempo real (con el conjunto de parches RT_PREEMPT) instalando el paquete rt kernel (al menos en Ubuntu 10.04 LTS).

EDITAR: Los kernels de corrección de Linux en tiempo no real tienen un intervalo de suspensión mínimo mucho más cercano a 1 ms que a 10 ms, pero varía de manera no determinista.

Joseph Lisee
fuente
8
En realidad, los kernels de Linux han tenido una tasa de tic más alta durante bastante tiempo, por lo que la suspensión "mínima" está mucho más cerca de 1 ms que de 10 ms. No está garantizado: otra actividad del sistema puede hacer que el kernel no pueda programar su proceso tan pronto como lo desee, incluso sin contención de la CPU. Eso es lo que los núcleos en tiempo real están tratando de arreglar, creo. Pero, a menos que realmente necesite un comportamiento en tiempo real, el simple hecho de usar una tasa de ticks alta (configuración de kernel HZ) le dará inactivos no garantizados pero de alta resolución en Linux sin usar nada especial.
Glenn Maynard
1
Sí, tienes razón, probé con Linux 2.6.24-24 y pude acercarme bastante a las tasas de actualización de 1000 Hz. En el momento en que estaba haciendo esto, también estaba ejecutando el código en Mac y Windows, por lo que probablemente me confundí. Sé que Windows XP tiene al menos una tasa de tic de unos 10 ms.
Joseph Lisee
En Windows 8 obtengo algo menos de 2ms
markmnl
2
Además, la precisión no solo depende del sistema operativo, sino de lo que hace el sistema operativo tanto en Windows como en Linux si están ocupados haciendo algo más importante sleep()de los documentos "el tiempo de suspensión puede ser más largo de lo solicitado por una cantidad arbitraria debido a la programación de otra actividad en el sistema ".
markmnl
55

La gente tiene razón sobre las diferencias entre los sistemas operativos y los kernels, pero no veo ninguna granularidad en Ubuntu y veo una granularidad de 1 ms en MS7. Sugerir una implementación diferente de time.sleep, no solo una tasa de tick diferente. Una inspección más cercana sugiere una granularidad de 1μs en Ubuntu por cierto, pero eso se debe a la función time.time que utilizo para medir la precisión. Comportamiento típico de time.sleep de Linux y Windows en Python

Wilbert
fuente
6
Es interesante cómo Linux ha optado por dormir siempre un poco más de lo solicitado, mientras que Microsoft ha optado por el enfoque opuesto.
jleahy
2
@jleahy: el enfoque de Linux tiene sentido para mí: el sueño es realmente una liberación de la prioridad de ejecución durante un período de tiempo después del cual una vez más se somete a la voluntad del programador (que puede o no programar su ejecución de inmediato) .
empotramiento
2
¿cómo obtuviste los resultados? ¿Podría proporcionar el código fuente? El gráfico parece un artefacto de usar diferentes temporizadores para medir el tiempo y el sueño (en principio, incluso podría usar la deriva entre los temporizadores como una fuente de aleatoriedad ).
jfs
1
@JF Sebastian: la función que utilicé está en socsci.ru.nl/wilberth/computer/sleepAccuracy.html . El tercer gráfico muestra un efecto similar al que ves, pero de solo 1 ‰.
Wilbert
1
@JF Sebastian Uso time.clock () en Windows
Wilbert
26

De la documentación :

Por otro lado, la precisión de time()y sleep()es mejor que sus equivalentes de Unix: los tiempos se expresan como números de punto flotante, time()devuelve el tiempo más exacto disponible (usando Unix gettimeofday donde esté disponible) y sleep()aceptará un tiempo con una fracción distinta de cero ( selectse usa Unix para implementar esto, donde esté disponible).

Y más específicamente wrt sleep():

Suspender la ejecución durante el número de segundos especificado. El argumento puede ser un número de coma flotante para indicar un tiempo de reposo más preciso. El tiempo de suspensión real puede ser menor que el solicitado porque cualquier señal capturada terminará la sleep()siguiente ejecución de la rutina de captura de esa señal. Además, el tiempo de suspensión puede ser más largo de lo solicitado por una cantidad arbitraria debido a la programación de otra actividad en el sistema.

Stephan202
fuente
1
¿Alguien puede explicar "porque cualquier señal detectada terminará el sueño () después de la ejecución de la rutina de captura de esa señal"? ¿A qué señales se refiere? ¡Gracias!
Diego Herranz
1
Las señales son como notificaciones que administra el sistema operativo ( en.wikipedia.org/wiki/Unix_signal ), significa que si el sistema operativo captó una señal, el sueño () finaliza después de tratar esa señal.
ArianJM
24

Aquí está mi seguimiento de la respuesta de Wilbert: lo mismo para Mac OS X Yosemite, ya que aún no se ha mencionado mucho.Comportamiento del sueño de Mac OS X Yosemite

Parece que la mayor parte del tiempo duerme aproximadamente 1,25 veces el tiempo que solicitas y, a veces, duerme entre 1 y 1,25 veces el tiempo que solicitas. Casi nunca (~ dos veces de 1000 muestras) duerme significativamente más de 1,25 veces el tiempo que solicitas.

Además (no se muestra explícitamente) la relación de 1,25 parece mantenerse bastante bien hasta que llega por debajo de 0,2 ms, después de lo cual comienza a volverse un poco borrosa. Además, el tiempo real parece establecerse en aproximadamente 5 ms más de lo solicitado después de que la cantidad de tiempo solicitada supera los 20 ms.

Nuevamente, parece ser una implementación completamente diferente sleep()en OS X que en Windows o cualquier kernal de Linux que Wilbert estuviera usando.

Tim Supinie
fuente
¿Podrías cargar el código fuente del punto de referencia en github / bitbucket?
jfs
3
He intentado que en mi máquina. El resultado es similar a la respuesta de @ Wilbert .
jfs
Supongo que la suspensión en sí es precisa, pero la programación de Mac OS X no es lo suficientemente precisa como para proporcionar CPU lo suficientemente rápido como para retrasar la activación desde la suspensión. Si el tiempo exacto para despertarse es importante, parece que el sueño debe establecerse en 0,75 veces el realmente solicitado y verificar el tiempo después del despertar y dormir repetidamente por cada vez menos hasta la hora correcta.
Mikko Rantalainen
16

¿Por qué no lo averigua?

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

Para el registro, obtengo un error de alrededor de 0.1ms en mi HTPC y 2ms en mi computadora portátil, ambas máquinas Linux.

Hormigas Aasma
fuente
10
Las pruebas empíricas le darán una visión muy limitada. Hay muchos kernels, sistemas operativos y configuraciones de kernel que afectan esto. Los kernels de Linux más antiguos tienen por defecto una tasa de tick más baja, lo que da como resultado una mayor granularidad. En la implementación de Unix, una señal externa durante la suspensión la cancelará en cualquier momento, y otras implementaciones pueden tener interrupciones similares.
Glenn Maynard
6
Bueno, por supuesto, la observación empírica no es transferible. Aparte de los sistemas operativos y los núcleos, hay muchos problemas transitorios que afectan esto. Si se requieren garantías estrictas en tiempo real, entonces se debe tener en cuenta todo el diseño del sistema, desde el hardware hasta el final. Acabo de encontrar los resultados relevantes considerando las afirmaciones de que 10 ms es la precisión mínima. No me siento como en casa en el mundo de Windows, pero la mayoría de las distribuciones de Linux han estado ejecutando núcleos tickless durante un tiempo. Con los multinúcleos que ahora prevalecen, es muy probable que se programe muy cerca del tiempo de espera.
Hormigas Aasma
4

Una pequeña corrección, varias personas mencionan que el sueño puede interrumpirse temprano con una señal. En los documentos 3.6 dice:

Modificado en la versión 3.5: la función ahora duerme al menos segundos incluso si el sueño es interrumpido por una señal, excepto si el manejador de señales genera una excepción (ver PEP 475 para la justificación).

user405
fuente
3

Realmente no puede garantizar nada sobre el sueño (), excepto que al menos hará el mejor esfuerzo para dormir siempre que lo haya dicho (las señales pueden matar su sueño antes de que se acabe el tiempo, y muchas más cosas pueden hacer que funcione largo).

Seguro que el mínimo que puede obtener en un sistema operativo de escritorio estándar será de alrededor de 16 ms (granularidad del temporizador más tiempo para cambiar de contexto), pero es probable que el% de desviación del argumento proporcionado sea significativo cuando lo intente dormir durante 10 segundos de milisegundos.

Las señales, otros subprocesos que sostienen el GIL, la diversión de programación del kernel, el paso de la velocidad del procesador, etc. pueden causar estragos en la duración de su subproceso / proceso.

Nick Bastin
fuente
3
La documentación dice lo contrario:> El tiempo de suspensión real puede ser menor que el solicitado porque cualquier señal capturada terminará el sueño () después de la ejecución de la rutina de captura de esa señal.
Glenn Maynard
Ah, justo, se arregló la publicación, aunque dormir más tiempo () es mucho más probable que dormir menos.
Nick Bastin
1
Dos años y medio después ... la documentación sigue estando. En Windows, las señales no terminan la suspensión (). Probado en Python 3.2, WinXP SP3.
Dave
Sí, pero las señales que se adelantan al sueño son inusuales, por ejemplo, KILL, la documentación también dice: "Además, el tiempo de suspensión puede ser más largo de lo solicitado en una cantidad arbitraria debido a la programación de otra actividad en el sistema". que es más típico.
markmnl
1
Singnals y Windows es una tontería. En Windows, Python time.sleep () espera en un ConsoleEvent para capturar cosas como Ctrl-C.
schlenk
1

Si necesita más precisión o tiempos de sueño más bajos, considere hacer los suyos propios:

import time

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

Probado esto recientemente en Python 3.7 en Windows 10. La precisión fue de alrededor de 1 ms.

Aleksandar Kiridžić
fuente
3
¿Cómo lo probaste?
Agustín Barrachina
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()

No use una variable para pasar el argumento de sleep (), debe insertar el cálculo directamente en sleep ()


Y el regreso de mi terminal

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

para descanso
fuente