8.3. לולאת האירועים

לולאת האירועים היא המנוע ש-asyncio מריץ מתחת. היא שומרת רשימה של כל משימה בתוכנית, מבקשת מכל אחת לרוץ עד ה-await הבא של אותה משימה, ועוברת למשימה המוכנה הבאה. כאשר אין משימות מוכנות היא ממתינה – ההמתנה בפועל היא מה שמאפשר ל-CPU להיות זמין לקושחה כדי להריץ דברים אחרים ולהפעלת שינות חיסכון בחשמל – עד שמשהו שמשימה המתינה לו הופך לזמין, ואז מחדשת את אותה משימה. חוזרים על כך לנצח.

רוב האפליקציות לעולם אינן מקיימות אינטראקציה ישירה עם הלולאה. הלולאה היא תוצאה של קריאה ל-asyncio.run(); האפליקציה כותבת קורוטינות, מתזמנת אותן כמשימות, והלולאה עושה את השאר.

8.3.1. מה asyncio.run() עושה בפועל

קריאה יחידה:

asyncio.run(main())

היא קיצור לרצף ארוך יותר שהלולאה מנהלת בשם האפליקציה:

  1. צור את לולאת האירועים אם היא אינה קיימת כבר.

  2. עטוף את הקורוטינה שסופקה במשימה ותזמן אותה כנקודת הכניסה ברמה העליונה של הלולאה.

  3. הרץ את הלולאה – עבור צעד-צעד על משימות מוכנות, המתן כשאף אחת אינה מוכנה, חדש משימות כשקריאות ה-await שלהן מסתיימות – עד שהמשימה ברמה העליונה מחזירה ערך או זורקת חריגה.

  4. בטל כל משימה שהאפליקציה יצרה ושעדיין רצה.

  5. החזר את הערך שהקורוטינה ברמה העליונה החזירה (או זרוק מחדש את מה שהיא זרקה).

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()) הוא כל מה שאפליקציה זקוקה לו.