البرمجة

تنفيذ TaskCompletionSource بشكل متزامن

عند استخدام وظيفة TaskCompletionSource.SetResult() في بعض الحالات يتم تشغيل الاستمرار بشكل متزامن. بالرغم من الافتراض الشائع بأن جميع الاستمرارات تُنفذ على مجموعة متغيرة من الخيوط (باستخدام سياق تزامن افتراضي)، إلا أن هذا ليس الحال عند استخدام TaskCompletionSource.

في الشفرة التي قدمتها، تظهر دالة Bar() التي تُستدعى على خيط محدد، وتظل TaskCompletionSource غير مُعينة لبعض الوقت، مما يعني أن مهمة العودة لها (Task) تبقى بالحالة “غير مكتملة”. ثم بعد فترة من الزمن، يقوم نفس الخيط بدعوة _tcs.SetResult(x)، والتي من المفترض أن تُشغل الاستمرار على مجموعة الخيوط.

لكن اللاحظ الهام هو أن الخيط الذي يُشغل الاستمرار في الواقع لا يزال هو نفس الخيط، كما لو كان الاستمرار تم استدعاؤه متزامنًا مع SetResult. هذا يحير البعض، لكن هناك سبب لهذا التصرف.

عندما يكون الاستمرار بسيطًا بما فيه الكفاية، وتم إنشاؤه بواسطة async/await، وتم تعيين النتيجة باستخدام SetResult في سياق ذاتي الخيوط (self-contained context)، فإنه قد يتم تشغيل الاستمرار مباشرةً على الخيط الحالي، بدلاً من تأجيله إلى مجموعة الخيوط. هذا يحدث لأن الاستمرار يكون بسيطًا جدًا ولا يتطلب التأجيل أو التحكم في الاستمرار بشكل مختلف.

لتوضيح الأمر أكثر، فإن الاستمرار الذي يتم تشغيله بواسطة SetResult يُعتبر جزءًا من سلسلة التنفيذ الخطية، وعندما تكون الظروف ملائمة، يمكن تشغيلها على الفور. ومن الجدير بالذكر أن هذا السلوك لا يحدث دائمًا، بل يعتمد على العديد من العوامل بما في ذلك نوعية الاستمرار والسياق التنفيذي والظروف الحالية للبرنامج.

باختصار، يتم تشغيل SetResult بشكل متزامن مع الاستمرار في حالات معينة عندما تكون الظروف ملائمة، مما يسمح بتسريع التنفيذ وتحسين استجابة التطبيق في بعض الحالات.

المزيد من المعلومات

تحدث هذه الظاهرة بشكل أساسي عندما يكون الاستمرار بسيطًا ولا يتطلب معالجة خاصة أو تأخير. يمكن أن يحدث هذا في الحالات التي تشمل العمليات البسيطة التي يمكن تنفيذها بسرعة على نفس الخيط الذي قامت فيه SetResult بتعيين النتيجة.

يمكن أن تكون السيناريوهات التي تستفيد من هذا التصرف هي تلك التي تعتمد على الأداء العالي والاستجابة السريعة. فمثلاً، إذا كان لديك تطبيق يتفاعل مع الإدخال المستخدم بشكل مباشر، فإن استدعاء الاستمرار بشكل مباشر بدلاً من تأجيله يمكن أن يحسن من استجابة التطبيق بشكل ملحوظ.

ومع ذلك، يجب الانتباه إلى أن هذا السلوك ليس مطلوبًا في كل الحالات، وقد يكون غير مرغوب فيه في بعض الأحيان. فمن الضروري فهم طبيعة التطبيق ومتطلبات الأداء قبل الاعتماد على هذا التصرف.

بالإضافة إلى ذلك، يجب أن ندرك أن استدعاء الاستمرار بشكل متزامن ليس السلوك الافتراضي، ولكنه قد يحدث في حالات محددة فقط. ومن الأفضل دائمًا أن نكون على دراية بالتأثيرات المحتملة لهذا التصرف ونقيم ما إذا كان مناسبًا لتطبيقنا الخاص أم لا.

في النهاية، يجب أن نتذكر أن بناء تطبيقات قوية وفعالة ليس مجرد مسألة كتابة الشفرة، بل يتطلب فهماً عميقاً لأساسيات المفاهيم والسلوكيات وتقديرًا جيدًا للتداخلات المحتملة بين العناصر المختلفة في النظام.

زر الذهاب إلى الأعلى