Quiero ejecutar repetidamente una función en Python cada 60 segundos para siempre (al igual que un NSTimer en el Objetivo C). Este código se ejecutará como un demonio y es efectivamente como llamar al script de Python cada minuto usando un cron, pero sin requerir que el usuario lo configure.
En esta pregunta sobre un cron implementado en Python , la solución parece efectivamente dormir () durante x segundos. No necesito una funcionalidad tan avanzada, así que tal vez algo como esto funcione
while True:
# Code executed here
time.sleep(60)
¿Hay algún problema previsible con este código?
time.sleep(60)
puede regresar tanto antes como despuésRespuestas:
Si el programa no tiene un bucle de eventos ya, utilice el sched módulo, que implementa un planificador de eventos de propósito general.
Si ya está utilizando una biblioteca de bucles evento como
asyncio
,trio
,tkinter
,PyQt5
,gobject
,kivy
, y muchos otros - sólo programar la tarea utilizando los métodos de su biblioteca bucle de eventos existente, en vez.fuente
enterabs()
para evitarlo. Aquí hay una versión sin deriva para comparar .time.sleep
pueden acumularse aquí. "ejecutar cada X segundos" y "ejecutar con un retraso de ~ X segundos repetidamente" no son lo mismo. Ver también este comentarioBloquee su ciclo de tiempo en el reloj del sistema de esta manera:
fuente
twisted
respuesta son las únicas respuestas que ejecutan una función cadax
segundo. El resto ejecuta la función con un retraso dex
segundos después de cada llamada.from time import time, sleep
debido a las implicaciones existenciales;)starttime
si comienza sincronizándolo en un momento determinado:time.sleep(60 - time.time() % 60)
ha funcionado bien para mí. Lo he usado comotime.sleep(1200 - time.time() % 1200)
y me da registros en el:00 :20 :40
, exactamente como quería.sleep()
,timer()
la precisión y el tiempo que se tarda en ejecutar el cuerpo del bucle, pero en promedio iteraciones siempre se producen en los límites de intervalo (aunque algunos se saltan):while keep_doing_it(): sleep(interval - timer() % interval)
. Compárelo con solowhile keep_doing_it(): sleep(interval)
dónde se pueden acumular errores después de varias iteraciones.Es posible que desee considerar Twisted, que es una biblioteca de red de Python que implementa el patrón Reactor .
Mientras que "while True: sleep (60)" probablemente funcionará, Twisted probablemente ya implemente muchas de las características que eventualmente necesitará (demonización, registro o manejo de excepciones como lo señala bobince) y probablemente será una solución más sólida
fuente
Si desea una forma sin bloqueo para ejecutar su función periódicamente, en lugar de un bucle infinito de bloqueo, usaría un temporizador roscado. De esta manera, su código puede seguir ejecutándose y realizar otras tareas y aún así llamar su función cada n segundos. Utilizo mucho esta técnica para imprimir información de progreso en tareas largas intensivas de CPU / Disco / Red.
Aquí está el código que publiqué en una pregunta similar, con control start () y stop ():
Uso:
caracteristicas:
start()
ystop()
es seguro llamar varias veces incluso si el temporizador ya se ha iniciado / detenidointerval
cualquier momento, será efectivo después de la próxima ejecución. Lo mismo paraargs
,kwargs
e inclusofunction
!fuente
def _run(self)
que estoy tratando de envolver mi cabeza alrededor de eso que llamaself.start()
antesself.function()
. ¿Puedes elaborar? Pensaría que llamarstart()
primeroself.is_running
siempre seríaFalse
así, luego siempre giraríamos un nuevo hilo.x
segundo (es decir, t = 0, t = 1x, t = 2x, t = 3x, ...) donde en el póster original, el código de muestra ejecuta una función con un intervalo de x segundos entre ellos. Además, creo que esta solución tiene un error siinterval
es más corta que el tiempo que llevafunction
ejecutar. En ese caso,self._timer
se sobrescribirá en lastart
función..function()
after.start()
es ejecutar la función en t = 0. Y no creo que sea un problema sifunction
lleva más tiempointerval
, pero sí, podría haber algunas condiciones de carrera en el código.La forma más fácil que creo que es:
De esta manera, su código se ejecuta, luego espera 60 segundos y luego se ejecuta nuevamente, espera, ejecuta, etc. No es necesario complicar las cosas: D
fuente
time.sleep()
ejecutar algo cada X segundostime.sleep()
enwhile True
bucle como:def executeSomething(): print('10 sec left') ; while True: executeSomething(); time.sleep(10)
Si desea hacer esto sin bloquear el código restante, puede usar esto para permitir que se ejecute en su propio hilo:
Esta solución combina varias características que rara vez se encuentran combinadas en las otras soluciones:
threading.Timer
o lo que sea), esto terminará la cadena. Entonces no ocurrirán más ejecuciones, incluso si el motivo del problema ya está solucionado. Un bucle simple y esperando con un simplesleep()
es mucho más robusto en comparación.next_time += delay
en su lugar.fuente
Aquí hay una actualización del código de MestreLion que evita la deriva con el tiempo.
La clase RepeatedTimer aquí llama a la función dada cada segundo "intervalo" segundos según lo solicitado por el OP; la programación no depende de cuánto tiempo tarda la función en ejecutarse. Me gusta esta solución ya que no tiene dependencias de bibliotecas externas; Esto es simplemente Python puro.
Ejemplo de uso (copiado de la respuesta de MestreLion):
fuente
Me enfrenté a un problema similar hace algún tiempo. Puede ser http://cronus.readthedocs.org podría ayudar?
Para v0.2, el siguiente fragmento funciona
fuente
La principal diferencia entre eso y cron es que una excepción matará al demonio para siempre. Es posible que desee ajustar con un receptor y registrador de excepciones.
fuente
Una posible respuesta:
fuente
Terminé usando el módulo de programación . La API es buena.
fuente
Yo uso Tkinter después de método (), que no "robar el juego" (como el sched módulo que fue presentado anteriormente), es decir, permite otras cosas funcionen en paralelo:
do_something1()
ydo_something2()
puede correr en paralelo y en cualquier velocidad de intervalo. Aquí, el segundo se ejecutará el doble de rápido. Tenga en cuenta también que he usado un contador simple como condición para terminar cualquiera de las funciones. Puede usar cualquier otra configuración que desee o ninguna si desea ejecutar una función hasta que finalice el programa (por ejemplo, un reloj).fuente
after
no permite que las cosas se ejecuten en paralelo. Tkinter es de un solo subproceso y solo puede hacer una cosa a la vez. Siafter
se ejecuta algo programado por , no se ejecuta en paralelo con el resto del código. Si ambosdo_something1
ydo_something2
están programados para ejecutarse al mismo tiempo, se ejecutarán secuencialmente, no en paralelo.sched
solución y funcionará exactamente igual que la suya.Aquí hay una versión adaptada al código de MestreLion. Además de la función original, este código:
1) agregue first_interval utilizado para disparar el temporizador en un momento específico (la persona que llama necesita calcular el first_interval y pasar)
2) resuelve una condición de carrera en el código original. En el código original, si el hilo de control no pudo cancelar el temporizador en ejecución ("Detenga el temporizador y cancele la ejecución de la acción del temporizador. Esto solo funcionará si el temporizador todavía está en su etapa de espera". Citado en https: // docs.python.org/2/library/threading.html ), el temporizador se ejecutará sin fin.
fuente
Esto parece una solución mucho más simple que aceptada: ¿tiene algunas deficiencias que no estoy considerando? Vine aquí buscando un poco de pasta copia simple y me decepcionó.
Que sale asincrónicamente.
Tiene una deriva en el sentido de que si la tarea que se ejecuta lleva una cantidad de tiempo considerable, el intervalo se convierte en 2 segundos + tiempo de tarea, por lo que si necesita una programación precisa, entonces esto no es para usted.
Tenga en cuenta que la
daemon=True
bandera significa que este hilo no bloqueará el cierre de la aplicación. Por ejemplo, tuve un problema en el quepytest
se colgaría indefinidamente después de ejecutar las pruebas esperando que cesara este ataque.fuente
Lo uso para causar 60 eventos por hora y la mayoría de los eventos ocurren en la misma cantidad de segundos después de todo el minuto:
Dependiendo de las condiciones reales, puede obtener garrapatas de longitud:
pero al cabo de 60 minutos tendrás 60 ticks; y la mayoría de ellos ocurrirán en el desplazamiento correcto al minuto que prefiera.
En mi sistema obtengo una deriva típica de <1/20 de segundo hasta que surge la necesidad de corrección.
La ventaja de este método es la resolución de la deriva del reloj; lo que puede causar problemas si está haciendo cosas como agregar un elemento por marca y espera 60 elementos agregados por hora. No tener en cuenta la deriva puede causar indicaciones secundarias, como promedios móviles, para considerar datos demasiado profundos en el pasado, lo que resulta en una salida defectuosa.
fuente
por ejemplo, Mostrar la hora local actual
fuente
fuente
Aquí hay otra solución sin usar ninguna biblioteca adicional.
fuente