8.3. Pętla zdarzeń

Pętla zdarzeń to silnik, który asyncio uruchamia u podstaw. Utrzymuje listę każdego zadania w programie, prosi każde z nich o działanie do jego następnego await, a następnie przechodzi do kolejnego gotowego zadania. Gdy nie ma gotowych zadań, czeka — to właśnie faktyczne oczekiwanie udostępnia procesor oprogramowaniu układowemu do wykonywania innych rzeczy oraz umożliwia uruchomienie uśpień oszczędzających energię — aż coś, na co zadanie oczekiwało, stanie się dostępne, po czym wznawia to zadanie. Powtarzaj w nieskończoność.

Większość aplikacji nigdy nie wchodzi w bezpośrednią interakcję z pętlą. Pętla jest konsekwencją wywołania asyncio.run(); aplikacja pisze korutyny, szereguje je jako zadania, a pętla robi resztę.

8.3.1. Co tak naprawdę robi asyncio.run()

Pojedyncze wywołanie:

asyncio.run(main())

jest skrótem dla dłuższej sekwencji, którą pętla zarządza w imieniu aplikacji:

  1. Utwórz pętlę zdarzeń, jeśli jeszcze nie istnieje.

  2. Opakuj dostarczoną korutynę w zadanie i zaszereguj ją jako punkt wejścia najwyższego poziomu pętli.

  3. Uruchom pętlę — przechodź przez gotowe zadania, czekaj, gdy żadne nie jest gotowe, wznawiaj zadania, gdy ich instrukcje await się zakończą — do momentu, aż zadanie najwyższego poziomu zwróci wynik lub zgłosi wyjątek.

  4. Anuluj wszystkie zadania utworzone przez aplikację, które wciąż działają.

  5. Zwróć to, co zwróciła korutyna najwyższego poziomu (lub ponownie zgłoś to, co zgłosiła).

8.3.2. Jedna pętla na program

Asyncio w MicroPython ma jedną pętlę zdarzeń, i kropka. Nie ma tworzenia świeżej pętli ani zagnieżdżania jednej pętli wewnątrz drugiej. Wywołanie asyncio.run() z wnętrza korutyny, która już działa w pętli, jest błędem; pętla już tam jest, a korutyna musi po prostu wykonać await na tym, co chciała uruchomić.

W praktyce reguła jest taka sama jak końcowy wiersz poprzedniej strony: na program przypada dokładnie jedno wywołanie asyncio.run(), na samej górze, z pojedynczym async def main() za nim. Wszystko inne mieści się wewnątrz main.

8.3.3. Bezpośredni dostęp do pętli

W rzadkich przypadkach, gdy aplikacja musi sięgnąć po samą pętlę — głównie diagnostyka i obsługa wyjątków — asyncio.get_event_loop() zwraca obiekt Loop. Stamtąd aplikacja może zainstalować własną obsługę wyjątków, sprawdzić, co pętla robi, lub (bardzo sporadycznie) wywołać create_task() bezpośrednio zamiast asyncio.create_task() (to ta sama operacja).

Pełny zestaw metod, które udostępnia Looprun_forever(), stop(), set_exception_handler() i pozostałe — omówiony jest na stronie sterowanie pętlą w dalszej części tej sekcji. Do tego czasu asyncio.run(main()) to wszystko, czego aplikacja potrzebuje.