asyncio — scheduler di I/O asincrono

Questo modulo fornisce uno scheduler a multitasking cooperativo per le coroutine async/await, insieme a primitive per la sincronizzazione (lock, eventi) e per il networking TCP non bloccante tramite reader e writer di stream. I task vengono eseguiti in modo concorrente su un singolo event loop; il task attualmente in esecuzione restituisce il controllo al loop con await.

Esempio:

import asyncio

async def blink(led, period_ms):
    while True:
        led.on()
        await asyncio.sleep_ms(5)
        led.off()
        await asyncio.sleep_ms(period_ms)

async def main(led1, led2):
    asyncio.create_task(blink(led1, 700))
    asyncio.create_task(blink(led2, 400))
    await asyncio.sleep_ms(10_000)

# Running on an OpenMV Cam
from machine import LED
asyncio.run(main(LED(1), LED(2)))

Funzioni principali

asyncio.create_task(coro: Coroutine) Task

Crea un nuovo task a partire dalla coroutine specificata e lo pianifica per l’esecuzione.

Restituisce il corrispondente oggetto Task.

asyncio.current_task() Task

Restituisce l’oggetto Task associato al task attualmente in esecuzione.

asyncio.run(coro: Coroutine) Any

Crea un nuovo task a partire dalla coroutine specificata e lo esegue fino al completamento.

Restituisce il valore restituito da coro.

asyncio.sleep(t: float) None

Mette in pausa per t secondi (può essere un float).

Questa è una coroutine.

asyncio.sleep_ms(t: int) None

Mette in pausa per t millisecondi.

Questa è una coroutine, oltre che un’estensione di MicroPython.

Funzioni aggiuntive

asyncio.wait_for(awaitable: Awaitable, timeout: float) Any

Attende il completamento di awaitable, ma lo annulla se richiede più di timeout secondi. Se awaitable non è un task, ne verrà creato uno a partire da esso.

Se si verifica un timeout, il task viene annullato e viene sollevata l’eccezione asyncio.TimeoutError: questa dovrebbe essere intercettata dal chiamante. Il task riceve asyncio.CancelledError, che può essere ignorata oppure intercettata usando try...except o try...finally per eseguire codice di pulizia.

Restituisce il valore restituito da awaitable.

Questa è una coroutine.

asyncio.wait_for_ms(awaitable: Awaitable, timeout: int) Any

Simile a wait_for(), ma timeout è un intero in millisecondi.

Questa è una coroutine, oltre che un’estensione di MicroPython.

asyncio.gather(*awaitables, return_exceptions: bool = False) List

Esegue tutti gli awaitables in modo concorrente. Tutti gli awaitables che non sono task vengono promossi a task.

Restituisce un elenco dei valori restituiti da tutti gli awaitables.

Questa è una coroutine.

class Task

class asyncio.Task

Questo oggetto incapsula una coroutine in un task in esecuzione. È possibile attendere i task usando await task, che attenderà il completamento del task e restituirà il valore restituito dal task stesso.

I task non dovrebbero essere creati direttamente; è preferibile usare create_task() per crearli.

cancel() None

Annulla il task iniettando in esso asyncio.CancelledError. Il task può ignorare questa eccezione. È possibile eseguire codice di pulizia intercettandola, oppure tramite try ... finally.

class Event

class asyncio.Event

Crea un nuovo evento che può essere usato per sincronizzare i task. Gli eventi partono nello stato azzerato.

is_set() bool

Restituisce True se l’evento è impostato, False altrimenti.

set() None

Imposta l’evento. Tutti i task in attesa dell’evento verranno pianificati per l’esecuzione.

Nota: questo metodo deve essere chiamato dall’interno di un task. Non è sicuro chiamarlo da un IRQ, da una callback dello scheduler o da un altro thread. Vedi ThreadSafeFlag.

clear() None

Azzera l’evento.

wait() None

Attende che l’evento venga impostato. Se l’evento è già impostato, restituisce immediatamente.

Questa è una coroutine.

class ThreadSafeFlag

class asyncio.ThreadSafeFlag

Crea un nuovo flag che può essere usato per sincronizzare un task con codice in esecuzione al di fuori del loop asyncio, come altri thread, IRQ o callback dello scheduler. I flag partono nello stato azzerato.

set() None

Imposta il flag. Se c’è un task in attesa del flag, questo verrà pianificato per l’esecuzione.

clear() None

Azzera il flag. Questo può essere usato per assicurarsi che un flag eventualmente impostato in precedenza sia azzerato prima di metterlo in attesa.

wait() None

Attende che il flag venga impostato. Se il flag è già impostato, restituisce immediatamente. Il flag viene automaticamente resettato al ritorno da wait.

Un flag può essere atteso solo da un singolo task alla volta.

Questa è una coroutine.

class Lock

class asyncio.Lock

Crea un nuovo lock che può essere usato per coordinare i task. I lock partono nello stato sbloccato.

Oltre ai metodi descritti di seguito, i lock possono essere usati in un’istruzione async with.

locked() bool

Restituisce True se il lock è bloccato, altrimenti False.

acquire() bool

Attende che il lock sia nello stato sbloccato e poi lo blocca in modo atomico. Solo un task alla volta può acquisire il lock.

Questa è una coroutine.

release() None

Rilascia il lock. Se ci sono task in attesa del lock, il successivo nella coda viene pianificato per l’esecuzione e il lock rimane bloccato. Altrimenti, se nessun task è in attesa, il lock diventa sbloccato.

Connessioni stream TCP

asyncio.open_connection(host: str, port: int, ssl: ssl.SSLContext | bool | None = None) Tuple[Stream, Stream]

Apre una connessione TCP verso l”host e la port specificati. L’indirizzo host verrà risolto usando socket.getaddrinfo(), che attualmente è una chiamata bloccante. Se ssl è un oggetto ssl.SSLContext, questo contesto viene usato per creare il trasporto; se ssl è True, viene usato un contesto predefinito.

Restituisce una coppia di stream: uno stream reader e uno stream writer. Solleverà un OSError specifico del socket se non è stato possibile risolvere l’host o se non è stato possibile stabilire la connessione.

Questa è una coroutine.

asyncio.start_server(callback: Callable, host: str, port: int, backlog: int = 5, ssl: ssl.SSLContext | None = None) Server

Avvia un server TCP sull”host e la port specificati. La callback verrà chiamata con le connessioni in ingresso accettate, e riceverà 2 argomenti: gli stream reader e writer della connessione.

Se ssl è un oggetto ssl.SSLContext, questo contesto viene usato per creare il trasporto.

Restituisce un oggetto Server.

Questa è una coroutine.

class asyncio.Stream

Questo rappresenta una connessione stream TCP. Per ridurre al minimo il codice, questa classe implementa sia un reader che un writer, e sia StreamReader che StreamWriter sono alias di questa classe.

get_extra_info(v: str) Any

Ottiene informazioni aggiuntive sullo stream, indicate da v. I valori validi per v sono: peername.

close() None

Chiude lo stream.

wait_closed() None

Attende la chiusura dello stream.

Questa è una coroutine.

read(n: int = -1) bytes

Legge fino a n byte e li restituisce. Se n non viene fornito oppure è -1, legge tutti i byte fino a EOF. Il valore restituito sarà un oggetto bytes vuoto se viene incontrato EOF prima della lettura di qualsiasi byte.

Questa è una coroutine.

readinto(buf: bytearray | memoryview) int

Legge fino a n byte in buf, con n pari alla lunghezza di buf.

Restituisce il numero di byte letti in buf.

Questa è una coroutine, oltre che un’estensione di MicroPython.

readexactly(n: int) bytes

Legge esattamente n byte e li restituisce come oggetto bytes.

Solleva un’eccezione EOFError se lo stream termina prima di leggere n byte.

Questa è una coroutine.

readline() bytes

Legge una riga e la restituisce.

Questa è una coroutine.

write(buf: bytes) None

Accumula buf nel buffer di output. I dati vengono scaricati solo quando viene chiamato Stream.drain(). Si consiglia di chiamare Stream.drain() immediatamente dopo aver chiamato questa funzione.

drain() None

Scarica (scrive) tutti i dati di output bufferizzati verso lo stream.

Questa è una coroutine.

class asyncio.Server

Questo rappresenta la classe server restituita da start_server(). Può essere usata in un’istruzione async with per chiudere il server all’uscita.

close() None

Chiude il server.

wait_closed() None

Attende la chiusura del server.

Questa è una coroutine.

Event Loop

asyncio.get_event_loop() Loop

Restituisce l’event loop usato per pianificare ed eseguire i task. Vedi Loop.

asyncio.new_event_loop() Loop

Resetta l’event loop e lo restituisce.

Nota: poiché MicroPython ha un solo event loop, questa funzione si limita a resettare lo stato del loop, non ne crea uno nuovo.

class asyncio.Loop

Questo rappresenta l’oggetto che pianifica ed esegue i task. Non può essere creato; usa invece get_event_loop().

create_task(coro: Coroutine) Task

Crea un task a partire dalla coro specificata e restituisce il nuovo oggetto Task.

run_forever() None

Esegue l’event loop finché non viene chiamato stop().

run_until_complete(awaitable: Awaitable) Any

Esegue l”awaitable specificato fino al suo completamento. Se awaitable non è un task, verrà promosso a task.

stop() None

Arresta l’event loop.

close() None

Chiude l’event loop.

set_exception_handler(handler: Callable) None

Imposta il gestore delle eccezioni da chiamare quando un Task solleva un’eccezione non intercettata. Il handler deve accettare due argomenti: (loop, context).

get_exception_handler() Callable | None

Ottiene il gestore delle eccezioni corrente. Restituisce il gestore, oppure None se non è impostato alcun gestore personalizzato.

default_exception_handler(context: dict) None

Il gestore delle eccezioni predefinito che viene chiamato.

call_exception_handler(context: dict) None

Chiama il gestore delle eccezioni corrente. L’argomento context viene passato direttamente ed è un dizionario contenente le chiavi: 'message', 'exception', 'future'.