8.3. حلقة الأحداث¶
حلقة الأحداث هي المحرّك الذي يعمل asyncio أسفله. فهي تحتفظ بقائمة بكل مهمة في البرنامج، وتطلب من كل واحدة أن تعمل حتى await التالي لتلك المهمة، ثم تنتقل إلى المهمة الجاهزة التالية. وعندما لا تكون هناك مهام جاهزة، تنتظر -- والانتظار الفعلي هو ما يجعل وحدة المعالجة المركزية متاحة للبرنامج الثابت لتشغيل أمور أخرى ولتفعيل عمليات السكون الموفّرة للطاقة -- حتى يصبح شيء كانت إحدى المهام تنتظره متاحًا، ثم تستأنف تلك المهمة. وكرّر ذلك إلى الأبد.
لا تتفاعل معظم التطبيقات مع الحلقة مباشرةً أبدًا. فالحلقة نتيجة لاستدعاء 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()) هو كل ما يحتاجه أي تطبيق.