الترحيل إلى واستخدام Async Await - Perl

أمور يجب مراعاتها عند إعادة كتابة الكود لاستخدام بناء الجملة async/await الجديد المقدم بواسطة Future::AsyncAwait.
في الجزء 1 تناولنا كيفية إعادة كتابة الكود الذي كان يستخدم Future العادي بمفرده لتسلسل العمليات، إلى استخدام بناء الجملة الأنيق async/await المقدم بواسطة Future::AsyncAwait. في هذا الجزء، سنلقي نظرة على كيفية التعامل مع الأشكال المختلفة للتكرار والتكرار المقدم بواسطة Future::Utils::repeat. سنختم بالنظر في كيفية التعامل مع الشروط وهياكل التزامن.
repeat كحلقة while
عند استخدام Future العادي، قد يكون من الصعب التعبير عن بنية الحلقات المتكررة مثل حلقات while، لذا يوفر Future::Utils أداة مفيدة، repeat، للمساعدة في كتابتها. الآن بعد أن أصبح بإمكاننا استخدام بناء الجملة async/await الكامل داخل الكود، لم نعد مضطرين لاستخدام ذلك، وبدلاً من ذلك يمكننا كتابة حلقة while عادية في كود Perl عادي، مع تعبيرات await داخلها.
حلقة while العادية في Perl تختبر شرطها في البداية مقارنة بحلقة repeat التي تختبر الشرط بعد التكرار الأول، لذا غالبًا ما يكون من أنظف الطرق كتابتها باستخدام حلقة while(1) مع استخدام last صريح للخروج من الحلقة بمجرد تحقق الشرط.

في حلقة repeat، من الشائع استخدام "المحاولة السابقة المستقبلية" الممررة كأول وسيط للكشف عما إذا كانت هذه المحاولة هي الأولى أم لا، لتقرير ما إذا كان يجب تطبيق فترة تأخير قبل المحاولة التالية. في هذه الحالة، يسمح لك استخدام آخر تحكم في الحلقة لحلقة while(1) العادية بتخطي مثل هذا التأخير ببساطة:

repeat كحلقة foreach
استخدام آخر لـ repeat هو لإنشاء حلقة تكرار عبر مجموعة من القيم. كما في السابق، يمكننا كتابة هذا باستخدام تعبير await داخل حلقة foreach عادية في Perl.

أحيانًا تُرافق حلقة repeat ... foreach وسيط otherwise لتوفير كود لما يحدث عند انتهاء الحلقة - ربما ينتج عنه حالة خطأ ما. حلقات foreach العادية في Perl لا تمتلك مكافئًا دقيقًا، ولكن في الحالة المحتملة أن تكون الحلقة هي الجزء النهائي من الكود في الدالة، يمكن استخدام تعبير return لتوفير النتيجة، ويمكن وضع كود التعامل مع الفشل بعد الحلقة.

عائلة دوال fmap
توفر دالة fmap والدوال ذات الأسماء المماثلة نسخة تدعم التزامن من عامل map في Perl. ونظرًا لأنها تأخذ وسيطًا إضافيًا للتحكم في مستوى التزامن، وحيث أن تعبيرات await لا تعمل حاليًا داخل عامل map في Perl (RT129748)، فمن الأفضل الاستمرار في استخدام fmap وما يشابهه حيثما أمكن.
لا تنسَ أنه بما أن fmap تُرجع Future، يمكنك الانتظار على النتيجة باستخدام await، وأن جسم الحلقة يمكن أن يكون دالة async فرعية، مما يسمح باستخدام تعبيرات await داخلها.


أحيانًا يكون "المسار الرئيسي" لمناداة Future->wait_any ليس مجرد استدعاء دالة واحد، بل مجموعة من العمليات، ربما في سلسلة ->then، أو حلقة repeat. في هذه الحالة، من الصعب قليلاً إعادة كتابة هذا المسار إلى بناء جملة async/await لأن تعبير await سيجعل الدالة الحاوية تتوقف، وبأي حال لا يعيد قيمة Future مناسبة للتمرير إلى ->wait_any.
في هذه الحالة، يمكننا استخدام دالة async فرعية داخلية لحصر المسار الرئيسي للكود مع تعبيرات await، وتنفيذها مباشرة.

تذكر أن return داخل حلقة foreach يجعل دالتها الحاوية ترجع، أي الدالة anonymous async الفرعية التي تُستدعى كوسيط ثاني في Future->wait_any. هذا يجعل من السهل إنهاء الحلقة هناك.
الشروط وهياكل التزامن
الشروط
أحد تركيبات الكود المزعجة بشكل خاص عند استخدام Future البسيط هو كيفية تنفيذ إجراء يُرجع future بشكل شرطي في تسلسل من الخطوات الأخرى. غالبًا ما يتضمن الحل التقليدي اختبار تحقق الشرط، وإذا لم يكن صحيحًا، الانتظار على future "وهمية" فورية لتغطية الحالة التي لا يتم فيها استدعاء الكود الشرطي. لأن await يمكن وضعها في أي مكان داخل دالة async فرعية، بما في ذلك داخل كتلة if عادية، يمكن تجنب تلك التركيبات المعقدة وكتابة كود أبسط بكثير بدلاً منها.

يمكن أيضًا استخدام كلمة await المفتاحية داخل اختبار شرط لكتلة if:

تدفق متقارب
غالبًا ما يكون هناك تزامن لعدة عمليات تتقارب في مكان واحد باستخدام Future->needs_all أو دوال أخرى ذات صلة في كود يعتمد على futures. وبما أن هذه المنشأة تُرجع future، فيمكننا استخدام await عليها كأي شيء آخر. ونظرًا لأن النتائج تُعاد في قائمة مرتبة بنفس ترتيب futures التي تنتظرها، فمن السهل جدًا فك هذه القائمة في تعيين قائمة:

وبالمثل، يمكن استخدام await على Future->wait_any، كما هو مستخدم مثلاً لتنفيذ مهلة زمنية:

في بعض الأحيان، يكون "المسار الرئيسي" لمناداة Future->wait_any ليس مجرد استدعاء دالة واحدة، بل مؤلفًا من عمليات متعددة، ربما في سلسلة ->then أو حلقة repeat. في هذه الحالة، يصعب قليلًا إعادة كتابة هذا المسار إلى بناء جملة async/await لأن تعبير await سيوقف الدالة الحاوية بأكملها، وبأي حال لا يعيد قيمة Future مناسبة للتمرير إلى ->wait_any.
في هذه الحالة، يمكننا استخدام دالة async فرعية داخلية لحصر المسار الرئيسي للكود مع تعبيرات await، وتنفيذها فورًا.

تذكر أن return داخل حلقة foreach يجعل دالة الحاوية ترجع، وهي الدالة async الفرعية المجهولة التي تُستدعى كوسيطة ثانية لـ Future->wait_any. وهذا يجعل إنهاء الحلقة هناك مريحًا.
ملاحظة: لقد تم نقل هذا المنشور من https://tech.binary.com/ (مدونتنا التقنية القديمة). مؤلف هذه المقالة هو https://metacpan.org/author/PEVANS