8.3. O ciclo de eventos¶
O ciclo de eventos é o motor que o asyncio executa por baixo. Mantém uma lista de cada tarefa no programa, pede a cada uma que execute até ao próximo await dessa tarefa, e passa para a próxima tarefa pronta. Quando não há tarefas prontas, aguarda – a espera real é o que torna o CPU disponível para o firmware executar outras coisas e para os sleeps de poupança de energia entrarem em ação – até que algo por que uma tarefa estava à espera fique disponível, depois retoma essa tarefa. Repete indefinidamente.
A maioria das aplicações nunca interage diretamente com o ciclo. O ciclo é uma consequência de chamar asyncio.run(); a aplicação escreve corrotinas, agenda-as como tarefas, e o ciclo faz o resto.
8.3.1. O que asyncio.run() faz na realidade¶
Uma única chamada:
asyncio.run(main())
é uma abreviatura de uma sequência mais longa que o ciclo gere em nome da aplicação:
Criar o ciclo de eventos se ainda não existir.
Envolver a corrotina fornecida numa tarefa e agendá-la como ponto de entrada de nível superior do ciclo.
Executar o ciclo – percorrer as tarefas prontas, aguardar quando nenhuma estiver pronta, retomar as tarefas quando os seus awaits concluírem – até que a tarefa de nível superior retorne ou lance uma exceção.
Cancelar quaisquer tarefas que a aplicação criou e que ainda estejam em execução.
Devolver o que a corrotina de nível superior devolveu (ou relançar o que ela lançou).
8.3.2. Um ciclo por programa¶
O asyncio do MicroPython tem um ciclo de eventos, ponto final. Não é possível criar um ciclo novo, nem aninhar um ciclo dentro de outro. Chamar asyncio.run() dentro de uma corrotina que já está a correr no ciclo é um erro; o ciclo já existe, e a corrotina simplesmente precisa de aguardar pelo que queria iniciar.
Na prática, a regra é a mesma que a linha de fecho da página anterior: existe exatamente uma chamada a asyncio.run() por programa, no topo, com um único async def main() por trás. Tudo o resto vive dentro de main.
8.3.3. Acesso direto ao ciclo¶
Para os casos raros em que uma aplicação precisa de tocar no próprio ciclo – principalmente diagnósticos e gestores de exceções – asyncio.get_event_loop() devolve o objeto Loop. A partir daí, a aplicação pode instalar um gestor de exceções personalizado, inspecionar o que o ciclo está a fazer, ou (muito ocasionalmente) chamar create_task() diretamente em vez de asyncio.create_task() (são a mesma operação).
O conjunto completo de métodos que Loop expõe – run_forever(), stop(), set_exception_handler(), e os restantes – é abordado na página de controlo do ciclo mais adiante nesta secção. Até lá, asyncio.run(main()) é tudo o que uma aplicação precisa.