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 بشكل طبيعي. أما المصادر التي لا تنتهي أبدًا -- تدفق مستشعر مستمر، أو اشتراك طويل الأمد -- فتعمل الحلقة حتى يتم إلغاء الكوروتين التي تعيش فيها أو هدم مهمتها.