¿Cómo me aseguro de que un ciclo while de Python demore un tiempo determinado en ejecutarse?

Estoy leyendo datos en serie con un bucle while. Sin embargo, no tengo control sobre la frecuencia de muestreo.

El código en sí parece tardar 0.2s en ejecutarse, así que sé que no podré ir más rápido que eso. Pero me gustaría poder controlar con precisión cuánto más lento muestro.

Siento que podría hacerlo usando el modo “dormir”, pero el problema es que existe la posibilidad de que en los diferentes puntos el propio bucle tarde más en leer (dependiendo de lo que se transmite sobre los datos en serie), por lo que el código tendría para compensar el equilibrio.

Por ejemplo, digamos que quiero muestrear cada 1s, y el bucle toma de 0.2s a 0.3s para ejecutarse. Mi código debe ser lo suficientemente inteligente como para dormir durante 0.8 s (si el bucle toma 0.2s) o 0.7s (si el bucle toma 0.3s).

import serial import csv import time #open serial stream while True: #read and print a line sample_value=ser.readline() sample_time=time.time()-zero sample_line=str(sample_time)+','+str(sample_value) outfile.write(sample_line) print 'time: ',sample_time,', value: ',sample_value 

Solo mide el tiempo de ejecución de tu código, toma cada iteración del bucle y sleep consecuencia:

 import time while True: now = time.time() # get the time do_something() # do your stuff elapsed = time.time() - now # how long was it running? time.sleep(1.-elapsed) # sleep accordingly so the full iteration takes 1 second 

Por supuesto, no es 100% perfecto (tal vez de un milisegundo u otro de vez en cuando), pero supongo que es lo suficientemente bueno.


Otro buen enfoque es usar LoopingCall :

 from twisted.internet import task from twisted.internet import reactor def do_something(): pass # do your work here task.LoopingCall(do_something).start(1.0) reactor.run() 

Al comienzo del bucle, compruebe si ha transcurrido el tiempo adecuado. Si no lo ha hecho, continue .

 # Set up initial conditions for sample_time outside the loop sample_period = ??? next_min_time = 0 while True: sample_time=time.time()-zero if sample_time < next_min_time: continue #read and print a line sample_value=ser.readline() sample_line=str(sample_time)+','+str(sample_value) outfile.write(sample_line) print 'time: ',sample_time,', value: ',sample_value next_min_time = sample_time + sample_period 

Un método bastante elegante es que estás trabajando en UNIX: usa la biblioteca de señales

El código :

 import signal def _handle_timeout(): print "timeout hit" # Do nothing here def second(count): signal.signal(signal.SIGALRM, _handle_timeout) signal.alarm(1) try: count += 1 # put your function here signal.pause() finally: signal.alarm(0) return count if __name__ == '__main__': count = 0 count = second(count) count = second(count) count = second(count) count = second(count) count = second(count) print count 

Y el tiempo:

  georgesl@cleese:~/Bureau$ time python timer.py 5 real 0m5.081s user 0m0.068s sys 0m0.004s 

Sin embargo, hay dos advertencias: solo funciona en * nix, y no es multihebra segura.