8.11. المكررات غير المتزامنة#

المكرِّر غير المتزامن هو نسخة asyncio من المكرِّر. قدّمت نظرة عامة على Python بروتوكول المكرِّر المتزامن -- __iter__ و __next__ -- وحلقة for التي تقوده. تضيف المكررات غير المتزامنة await إلى كل خطوة، فيتمكّن المكرِّر من الانتظار بين القيم دون حجب حلقة الأحداث.

8.11.1. البروتوكول#

يكون الصنف مكرِّرًا غير متزامن عندما يطبّق

  • __aiter__(self) -- يعيد كائن المكرِّر، وعادةً ما يكون self.

  • async def __anext__(self) -- يعيد القيمة التالية، أو يطلق StopAsyncIteration عندما لا يتبقى المزيد.

بنية الحلقة المقابلة هي async for

import asyncio


class FrameCounter:
    """Yield N integers, one per frame period."""

    def __init__(self, n, period_ms):
        self._n = n
        self._period_ms = period_ms
        self._i = 0

    def __aiter__(self):
        return self

    async def __anext__(self):
        if self._i >= self._n:
            raise StopAsyncIteration
        await asyncio.sleep_ms(self._period_ms)
        self._i += 1
        return self._i

async def main():
    async for n in FrameCounter(5, 200):
        print(n)

تنتظر حلقة async for كل استدعاء لـ __anext__، فتتنازل الكوروتين التي تشغّل الحلقة عن التحكم لحلقة الأحداث بين القيم تمامًا مثل أي await آخر.

8.11.2. متى تلجأ إليه#

كلما كان للتطبيق مصدر بيانات تصل بمرور الوقت وكان على المستهلك أن يكررها بكسل. مستشعر ينتج عينة لكل فترة، أو مقبس شبكة يسلّم رسائل، أو مولّد إطارات -- في أي مكان يناسبه الشكل while True: x = await source.next(); process(x)، يكون async for x in source هو الصياغة الأنظف.

بالنسبة للمصادر التي تبثّ حتى شرط نهاية محدّد، يطلق المكرِّر StopAsyncIteration وتخرج async for بشكل طبيعي. أما المصادر التي لا تنتهي أبدًا -- تدفق مستشعر مستمر، أو اشتراك طويل الأمد -- فتعمل الحلقة حتى يتم إلغاء الكوروتين التي تعيش فيها أو هدم مهمتها.