Inexcurate time.sleep () con Python 3.xy Windows 7

Después de esta publicación, he identificado una implementación no funcional de la función time.sleep () de Python en Windows 7 (Enterprise, 64-bit y Python 3.4.4).

Aquí está la referencia .py script:

import threading, time def Return(): return def Setup(): for _ in range(10): time_before = time.time() Return() wait_delay = -time.time() delays = [] InputFrequency = 60 while (time.time() - time_before) < (1 / InputFrequency): time.sleep(0) wait_delay += time.time() delays.append(wait_delay) print("Output frequency: " + str([1/t for t in delays][0]) + " Hz") threading.Thread(target=Setup).start() 

Según este ejemplo, este script debería producir frecuencias de salida de aproximadamente 60Hz. Sin embargo, cuando se ejecuta en mi máquina Windows 7 Enterprise, estas son las frecuencias de salida que recibo para una frecuencia de entrada determinada:

Entrada: 10Hz – Salida: 9.15Hz


Entrada: 20Hz – Salida: 16.03Hz


Entrada: 30Hz – Salida 21.37Hz


Rango de entrada: 40Hz – 64Hz – Salida: 32.05Hz


Rango de entrada: 65Hz – 10kHz + – Salida: 64.10Hz


¿Que esta pasando aqui? ¿Por qué las frecuencias de entrada variables (por encima de 40 Hz) producen la misma frecuencia de salida? ¿Por qué el límite superior de la frecuencia de salida es 64.10Hz, incluso cuando la frecuencia de entrada es superior a 10,000Hz? No creo que sea un problema de resolución time.sleep () a ~ 60Hz. Los mismos valores de frecuencia de entrada suministrados a la secuencia de comandos ideone.com producen las frecuencias de salida esperadas, por lo que deben estar relacionadas con mi computadora.

Python ofrece muy pocas garantías sobre el comportamiento de estas llamadas, especialmente en plataformas cruzadas. Hay dos cosas que potencialmente pueden salir mal aquí: la time.time() es peor que la resolución que estás tratando de lograr o la resolución del sleep es.

El sueño debería ser aproximadamente de 1 a 2 ms de precisión en las plataformas recientes, como se informa aquí:

¿Qué precisión tiene Python’s time.sleep ()?

Esto deja time.time() . La documentación para esta llamada en particular advierte que la precisión puede ser deficiente:

Tenga en cuenta que aunque el tiempo siempre se devuelve como un número de punto flotante, no todos los sistemas proporcionan el tiempo con una precisión mejor que 1 segundo. Si bien esta función normalmente devuelve valores no decrecientes, puede devolver un valor más bajo que una llamada anterior si el reloj del sistema se ha establecido entre las dos llamadas.

Afortunadamente, se proporciona una API de reloj de mayor resolución en time.perf_counter() que intenta acceder al reloj de mayor resolución disponible en la plataforma. De la documentación:

Devuelva el valor (en fracciones de segundos) de un contador de rendimiento, es decir, un reloj con la resolución más alta disponible para medir una duración corta. Incluye el tiempo transcurrido durante la suspensión y se aplica a todo el sistema. El punto de referencia del valor devuelto no está definido, por lo que solo la diferencia entre los resultados de llamadas consecutivas es válida.

En el caso de Windows, esto parece ser mejor que 60Hz, lo que corrige su problema.