2015-01-06 4 views
32

Ho il seguente codice:Quando si utilizza asyncio, come si fa a consentire tutte le attività in esecuzione per finire prima di arrestare il ciclo degli eventi

@asyncio.coroutine 
def do_something_periodically(): 
    while True: 
     asyncio.async(my_expensive_operation()) 
     yield from asyncio.sleep(my_interval) 
     if shutdown_flag_is_set: 
      print("Shutting down") 
      break 

ho eseguito questa funzione fino al completo. Il problema si verifica quando viene impostato lo spegnimento: la funzione viene completata e le attività in sospeso non vengono mai eseguite. (Si vede questo come un errore

task: <Task pending coro=<report() running at script.py:33> wait_for=<Future pending cb=[Task._wakeup()]>> 

). Come posso programmare un arresto in modo corretto?

Per fornire un contesto, sto scrivendo un monitor di sistema che legge/proc/stat ogni 5 secondi, calcola l'utilizzo della CPU in quel periodo e quindi invia il risultato a un server. Voglio continuare a pianificare questi lavori di monitoraggio fino a quando non ricevo il sigterm, quando smetto di pianificare, attendo che tutti i lavori in corso finiscano, e esco con garbo.

+0

a dare qualche contesto, sto scrivendo un monitor di sistema che legge da/proc/stat ogni 5 secondi , calcola l'utilizzo della CPU in quel periodo, quindi invia il risultato a se stesso rver. Voglio continuare a pianificare questi lavori di monitoraggio fino a quando non ricevo il sigterm, quando smetto di pianificare, attendo che tutti i lavori in corso finiscano, e esco con garbo. – derekdreery

+0

hai provato 'rendimento da my_expensive_operation() \ n rendimento da asyncio.sleep (mio_interval - timer()% mio_interval)' invece? – jfs

+0

Potrei semplicemente dormire abbastanza a lungo da sapere che tutto è finito, ma questo non sembra molto pulito. Mi chiedevo se ci fosse un modo per pianificare le attività e quindi eseguire il ciclo fino a quando tutte le attività pianificate sono state completate. In javascript (node.js), se il programma principale raggiunge la fine ma sono state impostate le callback, il processo viene eseguito fino alla rimozione di tutte le richiamate. – derekdreery

risposta

33

È possibile recuperare attività non completate ed eseguire nuovamente il ciclo fino al termine, quindi chiudere il ciclo o uscire dal programma.

pending = asyncio.Task.all_tasks() 
loop.run_until_complete(asyncio.gather(*pending)) 
  • attesa è un elenco di attività in sospeso.
  • asyncio.gather() consente di attendere più attività contemporaneamente.

Se si vuole garantire tutte le attività sono completate all'interno di un coroutine (forse hai un coroutine "principale"), si può fare in questo modo, per esempio:

@asyncio.coroutine 
def do_something_periodically(): 
    while True: 
     asyncio.async(my_expensive_operation()) 
     yield from asyncio.sleep(my_interval) 
     if shutdown_flag_is_set: 
      print("Shutting down") 
      break 

    yield from asyncio.gather(*asyncio.Task.all_tasks()) 

Inoltre questo caso, dal momento che tutte le attività sono creati nella stessa coroutine, che già hanno accesso alle funzioni:

@asyncio.coroutine 
def do_something_periodically(): 
    tasks = [] 
    while True: 
     tasks.append(asyncio.async(my_expensive_operation())) 
     yield from asyncio.sleep(my_interval) 
     if shutdown_flag_is_set: 
      print("Shutting down") 
      break 

    yield from asyncio.gather(*tasks) 
+1

Molto utile! Solo una nota sul secondo metodo: io * penso * che ogni attività che aggiungi alla lista rappresenti un descrittore di file aperto - questo significa che su Linux, potresti raggiungere il limite del file aperto ('ulimit -n') prima la coroutine è finita. – detly

+0

Ciao, cosa intendi con "rappresenta"? AFAIK, le attività non aprono gli oggetti file. –

+0

Ho trovato, usando il secondo metodo, che ricevo messaggi di errore riguardo l'avere troppi descrittori di file aperti. Penso * che ogni attività richieda un descrittore di file per funzionare. Nota che un "descrittore di file" non è la stessa cosa di un file aperto, potrebbero essere anche quelli usati da ['select()'] (http://www.gnu.org/software/libc/manual/ html_node/attesa-per-I_002fO.html # index-file-descriptor-sets_002c-for-select) call (che credo utilizzi la libreria 'asyncio'). Quindi se hai un limite di poche migliaia di descrittori di file aperti e molte altre attività, potresti riscontrare dei problemi. – detly

Problemi correlati