2.32. Corrotinas¶
Uma corrotina é uma função que pode pausar a meio da execução e retomar mais tarde a partir do ponto onde parou, com todas as suas variáveis locais intactas. Espelha o padrão do gerador – um corpo de função que pode ser suspenso e retomado – com uma diferença em quem conduz cada retoma.
A sintaxe do Python para escrever uma corrotina é o par de palavras-chave async / await. async marca a função como corrotina; await marca os pontos dentro dela onde é permitido pausar.
2.32.1. Definir uma corrotina¶
Uma função definida com async def é uma função corrotina. Chamá-la não executa o corpo; devolve um objeto corrotina que ainda não foi iniciado:
async def greet(name):
print("hello,", name)
coro = greet("Alice") # body NOT run yet
O objeto corrotina está pausado no início da função. Algo tem de a conduzir para que o corpo seja executado – esse algo é um ciclo de eventos, um componente de execução. O MicroPython inclui um no módulo asyncio. Por agora, trate a corrotina como «pronta a executar, à espera de um controlador».
2.32.2. Pausar dentro de uma corrotina¶
Dentro de uma corrotina, uma expressão await suspende a execução até que o valor aguardado esteja pronto:
async def fetch_and_log():
data = await read_sensor()
print("got:", data)
Quando o corpo chega a await read_sensor(), a corrotina devolve o controlo ao que a está a executar. Quando read_sensor() terminar, o controlador retoma a corrotina na linha seguinte, com o resultado ligado a data.
await só é válido dentro de uma corrotina. Utilizá-lo numa função regular é um erro de sintaxe.
2.32.3. Relação com os geradores¶
As corrotinas e os geradores partilham a mesma mecânica subjacente. A diferença está em quem desencadeia cada retoma:
Um gerador produz valores; o consumidor obtém o próximo com
next()ou por iteração.Uma corrotina produz controlo; um ciclo de eventos agenda a retoma quando a operação aguardada está pronta.
Se o mecanismo de entrega do gerador fizer sentido, o mecanismo da corrotina é a mesma ideia – apenas conduzido por um ciclo de eventos em vez de um ciclo for.
Um ciclo de eventos é um pequeno despachante que mantém uma lista de corrotinas à espera de algo (um temporizador, um evento de rede, outra corrotina a terminar). Em cada iteração, seleciona uma corrotina cuja espera foi satisfeita, retoma-a até ao próximo await, regista então o que essa corrotina aguarda agora e passa para outra que esteja pronta. O resultado é que muitas tarefas progridem de forma concorrente numa única thread – cada corrotina cede voluntariamente o controlo nos seus pontos await, e o ciclo preenche esses momentos com qualquer outra corrotina pronta para progredir.
Internamente, await e yield utilizam a mesma funcionalidade do tempo de execução do Python para suspender e retomar uma função. As palavras-chave diferem porque as convenções em torno delas diferem: yield devolve um valor a um consumidor que puxa com next(); await entrega o controlo a um ciclo de eventos que agenda a retoma quando a operação aguardada está pronta. async / await é essencialmente uma sintaxe mais recente para o padrão de corrotina – bibliotecas mais antigas construíam corrotinas diretamente sobre a maquinaria do gerador, usando yield from (introduzido em Iteradores e geradores) para delegar a suspensão entre corrotinas.
2.32.4. As corrotinas precisam de um controlador¶
Uma corrotina é inerte sem um tempo de execução que a conduza. Definir uma está correto; executar uma requer um ciclo de eventos. O módulo asyncio do MicroPython fornece esse ciclo de eventos. A secção Asyncio explica como iniciar o ciclo, agendar corrotinas nele, partilhar estado entre elas com cadeados e eventos, gerir cancelamento e timeouts, e estruturar uma aplicação real em torno das palavras-chave async / await introduzidas aqui.