sched — Programador de eventos cronometrados¶
Propósito: | Programador genérico de eventos. |
---|
El módulo sched
implementa un programador genérico de eventos para
ejecutar tareas en momentos específicos. La clase del programador utiliza una
función time
para conocer la hora actual y una función delay
para
esperar un período de tiempo específico. Las unidades de tiempo no son
importantes, lo que hace que la interfaz sea lo suficientemente flexible como
para ser utilizada para muchos propósitos.
La función time
se llama sin ningún argumento, y debe devolver un número
que represente la hora actual. La función delay
se llama con un único
argumento entero, usando la misma escala que la función de tiempo, y debe
esperar tantas unidades de tiempo antes de regresar. Por defecto,
monotonic()
y sleep()
de time
se usan, pero los ejemplos en esta
sección usan time.time()
, que también cumple con los requisitos, porque
hace que la salida sea más fácil de entender.
Para admitir aplicaciones multiproceso, la función de retraso se llama con el argumento 0 después de que se genera cada evento, para garantizar que otros subprocesos también tengan la oportunidad de ejecutarse.
Ejecución de eventos con retraso¶
Eventos pueden programarse para ejecutarse después de un retraso o en un
momento específico. Para programarlos con una demora, usa el método
enter()
, que toma cuatro argumentos.
- Un número que representa el retraso
- Un valor de prioridad
- La función a llamar
- Una tupla de argumentos para la función
Este ejemplo programa dos eventos diferentes para que se ejecuten después de
dos y tres segundos respectivamente. Cuando llega el momento del evento, se
llama a print_event()
e imprime la hora actual y el argumento del nombre
pasado al evento.
import sched
import time
scheduler = sched.scheduler(time.time, time.sleep)
def print_event(name, start):
now = time.time()
elapsed = int(now - start)
print('EVENT: {} elapsed={} name={}'.format(
time.ctime(now), elapsed, name))
start = time.time()
print('START:', time.ctime(start))
scheduler.enter(2, 1, print_event, ('first', start))
scheduler.enter(3, 1, print_event, ('second', start))
scheduler.run()
Ejecutar el programa produce:
$ python3 sched_basic.py
START: Sun Sep 4 16:21:01 2016
EVENT: Sun Sep 4 16:21:03 2016 elapsed=2 name=first
EVENT: Sun Sep 4 16:21:04 2016 elapsed=3 name=second
El tiempo impreso para el primer evento es dos segundos después del inicio, y el tiempo para el segundo evento es tres segundos después del inicio.
Eventos superpuestos¶
La llamada a run()
bloquea hasta que se hayan procesado todos los eventos.
Cada evento se ejecuta en el mismo hilo, por lo que si un evento tarda más en
ejecutarse que el retraso entre eventos, se superpondrá. La superposición se
resuelve posponiendo el evento posterior. No se pierden eventos, pero algunos
eventos se pueden llamar más tarde de lo programado. En el siguiente ejemplo,
long_event()
duerme pero podría retrasarse fácilmente realizando un cálculo
largo o bloqueando la E/S.
import sched
import time
scheduler = sched.scheduler(time.time, time.sleep)
def long_event(name):
print('BEGIN EVENT :', time.ctime(time.time()), name)
time.sleep(2)
print('FINISH EVENT:', time.ctime(time.time()), name)
print('START:', time.ctime(time.time()))
scheduler.enter(2, 1, long_event, ('first',))
scheduler.enter(3, 1, long_event, ('second',))
scheduler.run()
El resultado es que el segundo evento se ejecuta inmediatamente después de que finaliza el primero, ya que el primer evento tardó lo suficiente como para adelantar el tiempo deseado al segundo evento.
$ python3 sched_overlap.py
START: Sun Sep 4 16:21:04 2016
BEGIN EVENT : Sun Sep 4 16:21:06 2016 first
FINISH EVENT: Sun Sep 4 16:21:08 2016 first
BEGIN EVENT : Sun Sep 4 16:21:08 2016 second
FINISH EVENT: Sun Sep 4 16:21:10 2016 second
Prioridades del evento¶
Si se programa más de un evento al mismo tiempo, sus valores de prioridad se utilizan para determinar el orden en que se ejecutan.
import sched
import time
scheduler = sched.scheduler(time.time, time.sleep)
def print_event(name):
print('EVENT:', time.ctime(time.time()), name)
now = time.time()
print('START:', time.ctime(now))
scheduler.enterabs(now + 2, 2, print_event, ('first',))
scheduler.enterabs(now + 2, 1, print_event, ('second',))
scheduler.run()
Este ejemplo debe garantizar que estén programados para la misma hora exacta,
por lo que se utiliza el método enterabs()
en lugar de enter()
. El
primer argumento para enterabs()
es el tiempo para ejecutar el evento, en
lugar del tiempo de retraso.
$ python3 sched_priority.py
START: Sun Sep 4 16:21:10 2016
EVENT: Sun Sep 4 16:21:12 2016 second
EVENT: Sun Sep 4 16:21:12 2016 first
Cancelar eventos¶
Tanto enter()
como enterabs()
devuelven una referencia al evento que se
puede usar para cancelarlo más tarde. Debido a que run()
bloquea, el
evento debe cancelarse en un hilo diferente. Para este ejemplo, se inicia un
subproceso para ejecutar el planificador y el subproceso de procesamiento
principal se utiliza para cancelar el evento.
import sched
import threading
import time
scheduler = sched.scheduler(time.time, time.sleep)
# Set up a global to be modified by the threads
counter = 0
def increment_counter(name):
global counter
print('EVENT:', time.ctime(time.time()), name)
counter += 1
print('NOW:', counter)
print('START:', time.ctime(time.time()))
e1 = scheduler.enter(2, 1, increment_counter, ('E1',))
e2 = scheduler.enter(3, 1, increment_counter, ('E2',))
# Start a thread to run the events
t = threading.Thread(target=scheduler.run)
t.start()
# Back in the main thread, cancel the first scheduled event.
scheduler.cancel(e1)
# Wait for the scheduler to finish running in the thread
t.join()
print('FINAL:', counter)
Se programaron dos eventos, pero el primero se canceló más tarde. Solo se ejecuta el segundo evento, por lo que la variable de contador solo se incrementa una vez.
$ python3 sched_cancel.py
START: Sun Sep 4 16:21:13 2016
EVENT: Sun Sep 4 16:21:16 2016 E2
NOW: 1
FINAL: 1
Ver también
- Documentación de la biblioteca estándar para sched
time
– El módulotime
.