sched - Schedulatore di eventi per uso generale

Scopo Schedulatore di eventi per uso generale
Versione Python 1.4

Il modulo sched implementa uno schedulatore di eventi per eseguire dei compiti ad un tempo specificato. La classe scheduler usa una funzione time per acquisire l'ora attuale, ed una funzione delay per attendere uno specifico periodo di tempo. Le reali unità di tempo non sono importanti, cosa che rende l'interfaccia sufficientemente flessibile per essere usata per diversi scopi.

La funzione time viene chiamata senza parametri, e dovrebbe restituire un numero che corrisponde all'ora attuale. La funzione delay viene chiamata con un singolo intero come parametro, usando la stessa scala della funzione time, e dovrebbe attendere le unità temporali rappresentate da quel parametro prima di ritornare. Ad esempio le funzioni time.time() e time.sleep() soddisfano questi requisiti.

Per supportare le applicazioni multi-threaded, la funzione delay viene chiamata con parametro 0 dopo che ogni evento viene generato, per assicurare che gli altri thread abbiano anch'essi la possibilità di venire eseguiti.

Eseguire Eventi con Differimento

Gli eventi possono essere schedulati per essere eseguiti dopo un differimento, oppure ad una certa ora. Per schedularli con differimento, si usa il metodo enter(), che chiede 4 parametri:

  • Un numero che rappresenta il differimento
  • Un valore di priorità
  • La funzione da chiamare
  • Una tuple di parametri per la funzione

Questo esempio schedula due eventi diversi da eseguire rispettivamente dopo 2 e 3 secondi. Quando è l'ora di eseguire l'evento, viene chiamata print_event() che stampa l'ora attuale ed il parametro name passato all'evento

import sched
import time

scheduler = sched.scheduler(time.time, time.sleep)

def print_event(name):
    print 'EVENTO:', time.time(), name

print 'INIZIO:', time.time()
scheduler.enter(2, 1, print_event, ('primo',))
scheduler.enter(3, 1, print_event, ('secondo',))

scheduler.run()

L'output è qualcosa di simile a:

$ python sched_basic.py
INIZIO: 1253463104.94
EVENTO: 1253463106.94 primo
EVENTO: 1253463107.94 secondo

L'orario stampato per il primo evento è due secondi dopo la partenza, e l'orario del secondo evento è 3 secondi dopo la partenza.

Eventi Sovrapposti

La chiamata a run() blocca fino a che tutti gli eventi sono stati elaborati. Ogni evento viene eseguito nello stesso thread, in modo che se un evento necessita di un tempo di esecuzione maggiore rispetto a quello del differimento tra gli eventi, essi saranno sovrapposti. La sovrapposizione viene risolta posponendo l'evento che è più avanti nel tempo. Nessun evento viene perso, ma alcuni eventi potrebbero essere chiamati più tardi del previsto. Nel prossimo esempio long_event() contiene una istruzione di sleep ma il ritardo potrebbe essere facilmente determinato da un un lungo calcolo o da un blocco su di una operazione di I/O.

import sched
import time

scheduler = sched.scheduler(time.time, time.sleep)

def long_event(name):
    print 'INIZIO EVENTO :', time.time(), name
    time.sleep(2)
    print 'FINE EVENTO   :', time.time(), name

print 'PARTENZA:', time.time()
scheduler.enter(2, 1, long_event, ('primo',))
scheduler.enter(3, 1, long_event, ('secondo',))

scheduler.run()

Il risultato è che il secondo evento viene eseguito immediatamente dopo che finisce il primo, visto che per il primo evento ci è voluto abbastanza tempo per spingere l'orario dopo l'orario di partenza desiderato per il secondo evento.

$ python sched_overlap.py
PARTENZA: 1255906381.71
INIZIO EVENTO : 1255906383.71 primo
FINE EVENTO: 1255906385.71 primo
INIZIO EVENTO : 1255906385.71 secondo
FINE EVENTO: 1255906387.71 secondo

Priorità degli Eventi

Se più eventi vengono schedulati nello stesso tempo, i loro valori di priorità vengono usati per determinare l'ordine nel quale essi saranno eseguiti

import sched
import time

scheduler = sched.scheduler(time.time, time.sleep)

def print_event(name):
    print 'EVENTO:', time.time(), name

now = time.time()
print 'PARTENZA:', now
scheduler.enterabs(now+2, 2, print_event, ('primo',))
scheduler.enterabs(now+2, 1, print_event, ('secondo',))

scheduler.run()

Per essere sicuri che gli eventi siano schedulati allo stesso esatto orario, viene usato il metodo enterabs() in luogo di enter(). Il primo parametro per enterabs() è l'orario in cui eseguire l'evento, invece che il periodo di tempo di differimento.

$ python sched_priority.py
INIZIO: 1253463114.08
EVENTO: 1253463116.08 secondo
EVENTO: 1253463116.08 primo

Cancellare eventi

Sia enter() che enterabs() restituiscono un riferimento all'evento che può essere usato per cancellarlo successivamente. Visto il blocco di run(), l'evento deve essere eliminato in un thread differente. Per questo esempio, un thread viene lanciato per eseguire lo scheduler, quindi il thread di esecuzione principale viene usato per cancellare l'evento.

import sched
import threading
import time

scheduler = sched.scheduler(time.time, time.sleep)

# Imposta un valore globale perchè sia modificabile dai thread
counter = 0

def increment_counter(name):
    global counter
    print 'EVENTO:', time.time(), name
    counter += 1
    print 'ADESSO:', counter

print 'PARTENZA:', time.time()
e1 = scheduler.enter(2, 1, increment_counter, ('E1',))
e2 = scheduler.enter(3, 1, increment_counter, ('E2',))

# Inizia un thread per eseguire gli eventi
t = threading.Thread(target=scheduler.run)
t.start()

# Ritorna al thread principale, elimina il primo evento schedulato
scheduler.cancel(e1)

# Attende che lo the scheduler finisca l'esecuzione nel thread
t.join()

print 'FINALE:', counter

Sono stati schedulati due eventi, ma il primo successivamente è stato eliminato. Solo il secondo evento è stato eseguito, quindi la variabile counter viene incrementata una sola volta.

$ python sched_cancel.py
PARTENZA: 1253463116.24
EVENTO: 1253463119.24 E2
ADESSO: 1
FINALE: 1

Vedere anche:

sched
La documentazione della libreria standard per questo modulo.
time
Il modulo time