5.1 Event Loop
Ora accenniamo brevemente alla seconda parte dell'asincronicità, che emerge da tutte le parti: Event Loop, Task e Future.
Immagina l'Event Loop come un direttore d'orchestra, Task come i musicisti, e Future come le note che i musicisti devono suonare. Il direttore (Event Loop) coordina il lavoro dei musicisti (Task) che eseguono la musica (operazioni asincrone) leggendo le note (Future).
Il ciclo di eventi (Event Loop)
è il fulcro della programmazione asincrona in Python. È responsabile dell'esecuzione delle attività asincrone, della gestione degli eventi e dell'elaborazione dell'I/O. Il ciclo di eventi controlla continuamente la presenza di nuovi eventi o attività e li esegue quando sono pronti.
Funzioni principali
-
run_forever()
: Avvia il ciclo di eventi e continua la sua esecuzione fino alla chiamata distop()
. -
run_until_complete(future)
: Avvia il ciclo di eventi e lo termina dopo il completamento dell'oggetto futuro o della coroutine specificata. stop()
: Ferma il ciclo di eventi.-
create_task(coroutine)
: Pianifica l'esecuzione della coroutine come attività.
Esempio di utilizzo:
import asyncio
async def hello():
print("Hello, world!")
await asyncio.sleep(1)
print("Hello again!")
loop = asyncio.get_event_loop()
loop.run_until_complete(hello())
loop.close()
In questo esempio prima usiamo il metodo
get_event_loop()
per ottenere l'oggetto corrente
EventLoop
della libreria asyncio
.
Poi aggiungiamo a questo EventLoop
la coroutine hello
e gli chiediamo di eseguirla usando il metodo run_until_complete()
.
Nell'ultimo passaggio, chiudiamo il EventLoop
con l'aiuto del metodo close()
.
Quando esegui questo codice vedrai che prima viene stampato "Hello, world!", poi il programma aspetta 1 secondo, e dopo di che viene stampato "Hello again!". Questo dimostra come l'Event Loop gestisce l'esecuzione di una funzione asincrona.
Esamineremo queste azioni in modo più dettagliato nella prossima lezione.
5.2 Tasks
Le Task rappresentano un involucro per le coroutine, permettendo di gestire la loro esecuzione e monitorare il loro stato. Le Task permettono di eseguire le coroutine in parallelo, gestendole attraverso il ciclo di eventi.
Creazione e gestione delle Task
-
asyncio.create_task(coroutine)
: Crea una Task per l'esecuzione di una coroutine. -
Task.result()
: Restituisce il risultato della Task completata o solleva un'eccezione se la Task è terminata con un errore. Task.cancel()
: Annulla l'esecuzione della Task.
Esempio di utilizzo:
import asyncio
async def say_hello():
await asyncio.sleep(1)
print("Hello")
async def main():
task = asyncio.create_task(say_hello())
await task
asyncio.run(main())
In questo esempio avvolgiamo la coroutine say_hello()
con un oggetto Task
.
Anch'esso è un oggetto asincrono, quindi per ottenere il suo
risultato, dobbiamo applicare al suo interno l'operatore await
.
Quando esegui questo codice, il programma aspetta 1 secondo, e poi stampa "Hello". Questo mostra come la Task gestisce l'esecuzione della coroutine e come possiamo attendere il suo completamento usando await.
Più dettagli sulla gestione delle Task Task
verranno discussi nella prossima lezione.
5.3 Futures
Gli oggetti Future
rappresentano il risultato di un'operazione asincrona, che sarà disponibile in futuro. Consentono di gestire lo stato dell'operazione asincrona impostando il risultato o l'eccezione.
Metodi principali:
-
set_result(result)
: Imposta il risultato per l'oggettoFuture
. -
set_exception(exception)
: Imposta l'eccezione per l'oggettoFuture
. -
result()
: Restituisce il risultato dell'oggettoFuture
o solleva un'eccezione se l'operazione si è conclusa con un errore. -
exception()
: Restituisce l'eccezione se è stata impostata.
Esempio di utilizzo:
import asyncio
async def set_future(fut, value):
await asyncio.sleep(1)
fut.set_result(value)
async def main():
loop = asyncio.get_running_loop()
fut = loop.create_future()
await set_future(fut, 'Hello, future!')
print(fut.result())
asyncio.run(main())
In questo esempio creiamo un Future, impostiamo il suo valore dopo un secondo, e poi stampiamo il risultato. Vedrai che il programma aspetta un secondo prima di stampare 'Hello, future!'. Questo dimostra come Future rappresenta un risultato che diventerà disponibile in futuro.
A differenza di un oggetto Task
, un oggetto Future
è legato a un
Event Loop
specifico, e la funzione asincrona eseguita può scrivere in esso
il suo risultato. Anche se di solito funziona un po' diversamente.
Molto spesso, gli oggetti Future
vengono utilizzati in combinazione con le Task Task
, che forniscono una gestione più sofisticata delle operazioni asincrone.
Ora che ti sei familiarizzato con Event Loop
, Task
e Future
,
li esamineremo più da vicino.
GO TO FULL VERSION