8.3. Цикл подій¶
Цикл подій – це рушій, на якому працює asyncio. Він підтримує список кожної задачі в програмі, просить кожну виконуватися до наступного await цієї задачі, а потім переходить до наступної готової задачі. Коли немає готових задач, він чекає – саме це очікування робить CPU доступним для мікропрограми для виконання інших речей та для активації енергозберігаючих режимів сну – поки щось, чого чекала задача, не стане доступним, а потім відновлює задачу. І так до безкінечності.
Більшість програм ніколи не взаємодіє з циклом безпосередньо. Цикл є наслідком виклику asyncio.run(); програма пише корутини, планує їх як задачі, а цикл робить решту.
8.3.1. Що насправді робить asyncio.run()¶
Один виклик:
asyncio.run(main())
є скороченням для довшої послідовності, якою цикл керує від імені програми:
Створити цикл подій, якщо він ще не існує.
Обгорнути передану корутину в задачу та запланувати її як точку входу верхнього рівня циклу.
Запустити цикл – перебирати готові задачі, чекати коли жодна не готова, відновлювати задачі коли їхні await завершуються – до повернення або генерації винятку задачею верхнього рівня.
Скасувати всі задачі, створені програмою, які ще виконуються.
Повернути те, що повернула корутина верхнього рівня (або повторно генерувати виняток, який вона згенерувала).
8.3.2. Один цикл на програму¶
asyncio в MicroPython має один цикл подій, крапка. Не можна створити новий цикл і не можна вкласти один цикл в інший. Виклик asyncio.run() зсередини корутини, яка вже виконується на циклі, є помилкою; цикл вже є, і корутині просто потрібно await те, що вона хотіла запустити.
На практиці правило таке саме, як і кінцевий рядок попередньої сторінки: існує рівно один виклик asyncio.run() на програму, на початку, з одним async def main() за ним. Все інше знаходиться всередині main.
8.3.3. Прямий доступ до циклу¶
У рідкісних випадках, коли програмі потрібно торкнутися самого циклу – переважно в діагностиці та обробниках винятків – asyncio.get_event_loop() повертає об’єкт Loop. Звідти програма може встановити власний обробник винятків, перевірити, що робить цикл, або (дуже рідко) викликати create_task() напряму замість asyncio.create_task() (це одна й та сама операція).
Повний набір методів Loop – run_forever(), stop(), set_exception_handler() та інші – розглядається на сторінці керування циклом пізніше в цьому розділі. До того часу asyncio.run(main()) – це все, що потрібно програмі.