Dormir por hora exacta en Python

Necesito esperar unos 25ms en una de mis funciones. A veces, esta función se llama cuando el procesador está ocupado con otras cosas y otras veces tiene el procesador para sí mismo.

He intentado time.sleep(.25) pero a veces son 25ms y otras veces toma más tiempo. ¿Hay alguna manera de dormir durante un tiempo exacto independientemente de la disponibilidad del procesador?

Debido a que está trabajando con un sistema operativo preventivo , no hay forma de garantizar que su proceso podrá tener el control de la CPU en 25 ms.

Si aún desea probar, sería mejor tener un bucle ocupado que encueste hasta que hayan transcurrido 25 ms. Algo como esto podría funcionar:

 import time target_time = time.clock() + 0.025 while time.clock() < target_time: pass 

0.25 segundos son 250 ms, no 25. Aparte de esto, no hay forma de esperar exactamente 25 ms en los sistemas operativos comunes; necesitaría un sistema operativo en tiempo real.

¿En qué sistema estás? Si está en Windows, es posible que desee hacer algo como esto para la sincronización exacta:

 import ctypes kernel32 = ctypes.windll.kernel32 # This sets the priority of the process to realtime--the same priority as the mouse pointer. kernel32.SetThreadPriority(kernel32.GetCurrentThread(), 31) # This creates a timer. This only needs to be done once. timer = kernel32.CreateWaitableTimerA(ctypes.c_void_p(), True, ctypes.c_void_p()) # The kernel measures in 100 nanosecond intervals, so we must multiply .25 by 10000 delay = ctypes.c_longlong(.25 * 10000) kernel32.SetWaitableTimer(timer, ctypes.byref(delay), 0, ctypes.c_void_p(), ctypes.c_void_p(), False) kernel32.WaitForSingleObject(timer, 0xffffffff) 

Este código garantizará en gran medida que su proceso se suspenderá .25 segundos. Sin embargo, tenga cuidado: es posible que desee reducir la prioridad a 2 o 3, a menos que sea absolutamente crítico que esto duerma durante .25 segundos. Ciertamente, no cambie la prioridad demasiado alta para un producto final de usuario.

Lo que pretendes hacer es una aplicación en tiempo real. Python (y probablemente el sistema operativo que está utilizando) no está diseñado para progtwigr este tipo de aplicaciones, donde la restricción de tiempo es tan estricta.

Para que pueda lograr lo que busca, necesita un RTOS (sistema operativo en tiempo real) y desarrollar su aplicación utilizando un lenguaje de progtwigción adecuado (generalmente C) siguiendo las mejores prácticas de RT.

Edición: en Windows 10 este disparate parece innecesario. Inténtalo así:

 >>> from time import sleep >>> import timeit >>> '%.2f%% overhead' % (timeit.timeit('sleep(0.025)', number=100, globals=globals()) / 0.025 - 100) '0.29% overhead' 

El .29%, o aproximadamente, es un gasto general bastante bajo, y generalmente es más que suficientemente preciso.

Las versiones anteriores de Windows tendrán de forma predeterminada una resolución de suspensión de 55 ms, lo que significa que su llamada de suspensión tomará entre 25 y 55 ms. Para obtener una resolución de suspensión de 1 milisegundo, debe configurar la resolución utilizada por Windows llamando a timeBeginPeriod :

 import ctypes winmm = ctypes.WinDLL('winmm') winmm.timeBeginPeriod(1) 

De los documentos del método del sueño:

Suspender la ejecución por el número dado de segundos. El argumento puede ser un número de punto flotante para indicar un tiempo de suspensión más preciso. El tiempo de suspensión real puede ser inferior al solicitado porque cualquier señal capturada terminará el modo de suspensión () después de la 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 progtwigción de otra actividad en el sistema.

El hecho es que depende de su sistema operativo subyacente.

Otra solución para los tiempos precisos y el retraso es utilizar la función perf_counter () del tiempo del módulo. Especialmente útil en windows como time.sleep no es precisa en milisegundos. Vea el siguiente ejemplo donde la función accurate_delay crea un retraso en milisegundos.

 import time def accurate_delay(delay): ''' Function to provide accurate time delay in millisecond ''' _ = time.perf_counter() + delay/1000 while time.perf_counter() < _: pass delay = 10 t_start = time.perf_counter() print('Wait for {:.0f} ms. Start: {:.5f}'.format(delay, t_start)) accurate_delay(delay) t_end = time.perf_counter() print('End time: {:.5f}. Delay is {:.5f} ms'. format(t_end, 1000*(t_end - t_start))) sum = 0 ntests = 1000 for _ in range(ntests): t_start = time.perf_counter() accurate_delay(delay) t_end = time.perf_counter() print('Test completed: {:.2f}%'.format(_/ntests * 100), end='\r', flush=True) sum = sum + 1000*(t_end - t_start) - delay print('Average difference in time delay is {:.5f} ms.'.format(sum/ntests))