روتين دوري
قد لا يتوافق استخدام هذه المقالة للروابط الخارجية مع سياسات ويكيبيديا أو إرشاداتها . ( أبريل 2024 ) |
البرامج الفرعية هي مكونات برامج الكمبيوتر التي تسمح بتعليق التنفيذ واستئنافه، وتعميم البرامج الفرعية لتعدد المهام التعاوني . البرامج الفرعية مناسبة تمامًا لتنفيذ مكونات البرامج المألوفة مثل المهام التعاونية والاستثناءات وحلقات الأحداث والمكررات والقوائم اللانهائية والأنابيب .
وقد تم وصفها بأنها "وظائف يمكن إيقاف تنفيذها مؤقتًا". [1]
صاغ ميلفين كونواي مصطلح الروتين المشترك في عام 1958 عندما طبقه على بناء برنامج تجميع . [2] ظهر أول شرح منشور للروتين المشترك لاحقًا، في عام 1963. [3]
التعريف والأنواع
لا يوجد تعريف دقيق واحد للروتين التعاوني. في عام 1980، لخص كريستوفر د. مارلين [4] اثنتين من الخصائص الأساسية المعترف بها على نطاق واسع للروتين التعاوني:
- قيم البيانات المحلية للروتين التعاوني تظل قائمة بين المكالمات المتعاقبة؛
- يتم تعليق تنفيذ البرنامج الفرعي التعاوني عند خروج عنصر التحكم منه، فقط لاستكمال ما توقف عند عودة عنصر التحكم إلى البرنامج الفرعي التعاوني في مرحلة لاحقة.
بالإضافة إلى ذلك، فإن تنفيذ الروتين التعاوني يحتوي على 3 ميزات:
- آلية نقل التحكم. عادةً ما توفر البرامج الفرعية غير المتماثلة
yieldكلمات رئيسية مثل وresume. لا يمكن للمبرمجين اختيار الإطار الذي سيتم الخضوع له بحرية. لا يخضع وقت التشغيل إلا لأقرب متصل للبرنامج الفرعي الحالي. من ناحية أخرى، في البرامج الفرعية المتماثلة ، يجب على المبرمجين تحديد وجهة الخضوع. - ما إذا كانت البرامج الفرعية يتم توفيرها في اللغة ككائنات من الدرجة الأولى ، والتي يمكن للمبرمج التعامل معها بحرية، أو كإنشاءات مقيدة؛
- ما إذا كان بإمكان أحد البرامج الفرعية تعليق تنفيذه من داخل مكالمات الوظائف المتداخلة. مثل هذا البرنامج الفرعي هو برنامج فرعي مكدس . على العكس من ذلك، يُطلق عليه اسم البرامج الفرعية غير المكدسة ، حيث لا يمكن للوظيفة العادية استخدام الكلمة الأساسية . ما لم يتم تمييزها على أنها برنامج فرعي .
yield
في عام 2009، اقترحت ورقة بحثية بعنوان "إعادة النظر في الروتينات الفرعية" [5] مصطلح الروتين الفرعي الكامل للإشارة إلى الروتين الفرعي الذي يدعم الروتين الفرعي من الدرجة الأولى والذي يتسم بالتكديس. تستحق الروتينات الفرعية الكاملة اسمها الخاص لأنها تتمتع بنفس القوة التعبيرية مثل الاستمرارات أحادية اللقطة والاستمرارات المحددة. تكون الروتينات الفرعية الكاملة إما متماثلة أو غير متماثلة. ومن المهم أن كون الروتين الفرعي متماثلًا أو غير متماثل لا يؤثر على مدى قدرته على التعبير حيث أنهما متساويان في التعبير، على الرغم من أن الروتينات الفرعية الكاملة أكثر تعبيرًا من الروتينات الفرعية غير الكاملة. في حين أن قوتهما التعبيرية متماثلة، فإن الروتينات الفرعية غير المتماثلة تشبه بشكل أكبر هياكل التحكم القائمة على الروتين بمعنى أن التحكم يتم دائمًا إرجاعه إلى المستدعي، وهو ما قد يجده المبرمجون أكثر شيوعًا.
مقارنة مع
البرامج الفرعية
البرامج الفرعية هي حالات خاصة من البرامج الفرعية. [6] عندما يتم استدعاء البرامج الفرعية، يبدأ التنفيذ في البداية، وبمجرد خروج البرنامج الفرعي، ينتهي؛ تعود مثيلات البرنامج الفرعي مرة واحدة فقط، ولا تحتفظ بالحالة بين الاستدعاءات. على النقيض من ذلك، يمكن أن تخرج البرامج الفرعية عن طريق استدعاء برامج فرعية أخرى، والتي قد تعود لاحقًا إلى النقطة التي تم استدعاؤها فيها في البرنامج الفرعي الأصلي؛ من وجهة نظر البرنامج الفرعي، فإنه لا يخرج ولكنه يستدعي برنامجًا فرعيًا آخر. [6] وبالتالي، فإن مثيل البرنامج الفرعي يحتفظ بالحالة، ويختلف بين الاستدعاءات؛ يمكن أن يكون هناك مثيلات متعددة لروتين فرعي معين في وقت واحد. الفرق بين استدعاء برنامج فرعي آخر عن طريق "الاستسلام" له واستدعاء روتين آخر ببساطة (والذي سيعود أيضًا إلى النقطة الأصلية)، هو أن العلاقة بين اثنين من البرامج الفرعية التي تخضع لبعضها البعض ليست علاقة المتصل-المتصل به، بل هي علاقة متماثلة.
يمكن ترجمة أي برنامج فرعي إلى برنامج فرعي لا يستدعي yield . [7]
فيما يلي مثال بسيط لكيفية الاستفادة من الروتينات الفرعية. لنفترض أن لديك علاقة مستهلك-منتج حيث يقوم روتين واحد بإنشاء عناصر وإضافتها إلى قائمة انتظار ويقوم روتين آخر بإزالة العناصر من قائمة الانتظار واستخدامها. ولأسباب تتعلق بالكفاءة، تريد إضافة وإزالة عدة عناصر في وقت واحد. قد يبدو الكود على هذا النحو:
var q := قائمة انتظار جديدة
ينتج
الروتين الفرعي حلقة
بينما لا يكون q ممتلئًا
إنشاء بعض العناصر الجديدة
أضف العناصر إلى q
العائد للاستهلاك
يستهلك
الروتين الفرعي حلقة
بينما لا يكون q فارغًا
إزالة بعض العناصر من q
استخدم العناصر
العائد لإنتاج
اتصل بالإنتاج
يتم بعد ذلك ملء قائمة الانتظار أو إفراغها بالكامل قبل التنازل عن التحكم للروتين الفرعي الآخر باستخدام أمر yield . تبدأ استدعاءات الروتين الفرعي الأخرى مباشرة بعد yield ، في حلقة الروتين الفرعي الخارجي.
على الرغم من أن هذا المثال يستخدم غالبًا كمقدمة للتعدد في العمليات ، إلا أنه لا يلزم وجود خيطين لهذا: يمكن تنفيذ عبارة yield عن طريق القفز مباشرة من روتين إلى آخر.
الخيوط
البرامج الفرعية تشبه الخيوط إلى حد كبير . ومع ذلك، فإن البرامج الفرعية متعددة المهام بشكل تعاوني ، في حين أن الخيوط عادةً ما تكون متعددة المهام بشكل استباقي . توفر البرامج الفرعية التزامن ، لأنها تسمح بأداء المهام خارج الترتيب أو بترتيب قابل للتغيير، دون تغيير النتيجة الإجمالية، لكنها لا توفر التوازي ، لأنها لا تنفذ مهام متعددة في وقت واحد. تتمثل مزايا البرامج الفرعية على الخيوط في أنه يمكن استخدامها في سياق زمني حقيقي صعب ( لا يلزم التبديل بين البرامج الفرعية أن يتضمن أي مكالمات نظام أو أي مكالمات حظر على الإطلاق)، ولا توجد حاجة إلى بدائيات المزامنة مثل مفاتيح المزامنة المتبادلة ، وإشارات المرور، وما إلى ذلك من أجل حماية الأقسام الحرجة ، ولا توجد حاجة إلى دعم من نظام التشغيل.
من الممكن تنفيذ الروتينات التعاونية باستخدام مؤشرات ترابط مجدولة مسبقًا، بطريقة تكون شفافة لكود الاستدعاء، ولكن سيتم فقدان بعض المزايا (خاصة الملاءمة للتشغيل في الوقت الفعلي الصعب والرخص النسبي للتبديل بينها).
المولدات
المولدات، والمعروفة أيضًا باسم شبه الروتينات، [8] هي مجموعة فرعية من الروتينات الفرعية. على وجه التحديد، في حين يمكن لكليهما أن ينتجا مرات متعددة، مما يؤدي إلى تعليق تنفيذهما والسماح بإعادة الدخول عند نقاط دخول متعددة، إلا أنهما يختلفان في قدرة الروتينات الفرعية على التحكم في المكان الذي يستمر فيه التنفيذ فورًا بعد إنتاجهما، بينما لا تستطيع المولدات ذلك، بل تنقل التحكم بدلاً من ذلك إلى المتصل بالمولد. [9] أي، نظرًا لأن المولدات تُستخدم في المقام الأول لتبسيط كتابة المتكررات ، فإن yieldالبيان في المولد لا يحدد روتينًا فرعيًا للانتقال إليه، بل يمرر قيمة مرة أخرى إلى روتين رئيسي.
ومع ذلك، لا يزال من الممكن تنفيذ الروتينات التعاونية أعلى منشأة المولد، بمساعدة روتين المرسل عالي المستوى ( الترامبولين ، بشكل أساسي) الذي ينقل التحكم صراحةً إلى المولدات الفرعية التي تم تحديدها من خلال الرموز التي تم تمريرها مرة أخرى من المولدات:
var q := قائمة انتظار جديدة
المولد ينتج
حلقة
بينما q ليس ممتلئًا
إنشاء بعض العناصر الجديدة
أضف العناصر إلى q
أَثْمَر
مولد يستهلك
الحلقة
بينما q ليس فارغًا
إزالة بعض العناصر من q
استخدم العناصر
أَثْمَر
موزع
الروتين الفرعي var d := قاموس جديد ( مولد → متكرر )
d[إنتاج] := البدء في الاستهلاك
d[consume] := بدء إنتاج
متغير حالي := إنتاج
استدعاء حلقة
حالي
الحالي := التالي d[الحالي]
مُرسِل
المكالمات
يستخدم عدد من تنفيذات البرامج الفرعية للغات التي تدعم المولدات ولكن لا تحتوي على برامج فرعية أصلية (على سبيل المثال Python [10] قبل 2.5) هذا النموذج أو نموذجًا مشابهًا.
التكرار المتبادل
إن استخدام البرامج الفرعية المتكررة لآلات الحالة أو التزامن يشبه استخدام التكرار المتبادل مع استدعاءات الذيل ، حيث يتغير التحكم في كلتا الحالتين إلى عنصر تحكم مختلف من مجموعة من البرامج الفرعية. ومع ذلك، فإن البرامج الفرعية أكثر مرونة وأكثر كفاءة بشكل عام. نظرًا لأن البرامج الفرعية تنتج بدلاً من العودة، ثم تستأنف التنفيذ بدلاً من إعادة التشغيل من البداية، فهي قادرة على الاحتفاظ بالحالة، والمتغيرين (كما في الإغلاق) ونقطة التنفيذ، ولا تقتصر العائدات على كونها في موضع الذيل؛ يجب أن تستخدم البرامج الفرعية المتكررة المتبادلة إما المتغيرات المشتركة أو تمرر الحالة كمعلمات. علاوة على ذلك، تتطلب كل مكالمة متكررة متبادلة لبرنامج فرعي إطار مكدس جديد (ما لم يتم تنفيذ إزالة استدعاء الذيل )، بينما يستخدم تمرير التحكم بين البرامج الفرعية السياقات الموجودة ويمكن تنفيذه ببساطة عن طريق القفز.
الاستخدامات الشائعة
تعتبر البرامج الفرعية مفيدة لتنفيذ ما يلي:
- آلات الحالة داخل برنامج فرعي واحد، حيث يتم تحديد الحالة من خلال نقطة الدخول/الخروج الحالية للإجراء؛ يمكن أن يؤدي هذا إلى كود أكثر قابلية للقراءة مقارنة باستخدام goto ، ويمكن أيضًا تنفيذه عبر التكرار المتبادل مع مكالمات الذيل .
- نموذج الممثل للتزامن، على سبيل المثال في ألعاب الفيديو . كل ممثل لديه إجراءاته الخاصة (وهذا يفصل الكود منطقيًا مرة أخرى)، لكنه يتنازل طواعية عن السيطرة للمخطط المركزي، الذي ينفذها بشكل متسلسل (وهذا شكل من أشكال تعدد المهام التعاوني ).
- المولدات ، وهي مفيدة للتدفقات - وخاصة الإدخال/الإخراج - وللتنقل العام لهياكل البيانات.
- التواصل بين العمليات المتسلسلة حيث تكون كل عملية فرعية عبارة عن روتين فرعي. تؤدي مدخلات/مخرجات القناة وعمليات الحظر إلى إنشاء روتينات فرعية ويقوم المجدول بإلغاء حظرها عند أحداث الإكمال. بدلاً من ذلك، قد تكون كل عملية فرعية هي الأصل للعملية التالية لها في خط أنابيب البيانات (أو السابقة لها، وفي هذه الحالة يمكن التعبير عن النمط كمولدات متداخلة).
- الاتصال العكسي، المستخدم عادة في البرامج الرياضية، حيث تحتاج عملية مثل الحل أو التقييم التكاملي، إلى عملية الاستخدام لإجراء عملية حسابية، مثل تقييم معادلة أو تكامل.
الدعم الأصلي
نشأت الروتينات الفرعية كطريقة لغة التجميع ، ولكن يتم دعمها في بعض لغات البرمجة عالية المستوى .
- أيكيدو
- انجيل سكريبت
- راقصة باليه
- مدرسة كولومبيا البريطانية
- باسكال (Borland Turbo Pascal 7.0 مع وحدة uThreads)
- النسخة التجريبية
- النعيم
- C++ (منذ C++20)
- C# (منذ 2.0)
- كنيسة صغيرة
- تشاك
- كلو
- د
- ديناميكي سي
- إرلانج
- ف#
- عامل
- سكربت GameMonkey
- GDScript (لغة البرمجة النصية لـ Godot)
- هاسكل [11] [12]
- الجمعية رفيعة المستوى [13]
- رمز
- أيو
- JavaScript (منذ 1.7، تم توحيده في ECMAScript 6) [14] يتضمن ECMAScript 2017 أيضًا دعم await .
- جوليا [15]
- Kotlin (منذ 1.1) [16]
- ليمبو
- لوا [17]
- واضح
- ميكروسي++
- نموذج 2
- نيميرلي
- Perl 5 (باستخدام وحدة Coro)
- PHP (مع HipHop، أصلي منذ PHP 5.5)
- بيكوليسب
- برولوج
- بايثون (منذ 2.5، [18] مع دعم محسّن منذ 3.3 ومع بناء جملة صريح منذ 3.5 [19] )
- راكيت (لغة برمجة)
- راكو [20]
- روبي
- ساثر
- مخطط
- الذات
- المحاكاة 67 [21]
- محادثة قصيرة
- سنجاب
- بايثون بدون تكديس
- المصادم العملاق [22]
- Tcl (منذ 8.6)
- مخطوطة حضرية
نظرًا لأنه يمكن استخدام الاستمراريات لتنفيذ الروتينات التعاونية، فإن لغات البرمجة التي تدعمها يمكنها أيضًا دعم الروتينات التعاونية بسهولة تامة.
التنفيذات
اعتبارًا من عام 2003 [تحديث]، لا تحتوي العديد من لغات البرمجة الأكثر شيوعًا، بما في ذلك C ومشتقاتها، على دعم مدمج للروتينات الفرعية داخل اللغة أو مكتباتها القياسية. ويرجع هذا إلى حد كبير إلى قيود تنفيذ الروتينات الفرعية القائمة على المكدس . الاستثناء هو مكتبة C++ Boost.Context، وهي جزء من مكتبات Boost، والتي تدعم تبديل السياق على ARM وMIPS وPowerPC وSPARC وx86 على POSIX وMac OS X وWindows. يمكن بناء الروتينات الفرعية على Boost.Context.
في المواقف التي يكون فيها الروتين الفرعي هو التنفيذ الطبيعي لآلية ما، ولكنه غير متاح، فإن الاستجابة النموذجية هي استخدام الإغلاق - وهو روتين فرعي يحتوي على متغيرات حالة ( متغيرات ثابتة ، وغالبًا ما تكون أعلامًا منطقية) للحفاظ على حالة داخلية بين المكالمات، ونقل التحكم إلى النقطة الصحيحة. تؤدي الشروط داخل الكود إلى تنفيذ مسارات كود مختلفة على المكالمات المتعاقبة، بناءً على قيم متغيرات الحالة. استجابة نموذجية أخرى هي تنفيذ آلة حالة صريحة في شكل عبارة switch كبيرة ومعقدة أو عبر عبارة goto ، وخاصة goto المحسوبة . تعتبر مثل هذه التنفيذات صعبة الفهم والصيانة، وهي دافع لدعم الروتين الفرعي.
الخيوط ، وإلى حد أقل الألياف ، هي بديل للروتينات التعاونية في بيئات البرمجة السائدة اليوم. توفر الخيوط تسهيلات لإدارة التفاعل التعاوني في الوقت الفعلي لتنفيذ أجزاء من التعليمات البرمجية في وقت واحد . الخيوط متاحة على نطاق واسع في البيئات التي تدعم لغة C (وهي مدعومة بشكل أصلي في العديد من اللغات الحديثة الأخرى)، وهي مألوفة للعديد من المبرمجين، وعادة ما تكون منفذة جيدًا وموثقة جيدًا ومدعومة جيدًا. ومع ذلك، نظرًا لأنها تحل مشكلة كبيرة وصعبة، فإنها تتضمن العديد من المرافق القوية والمعقدة ولديها منحنى تعليمي صعب وفقًا لذلك. على هذا النحو، عندما يكون الروتين التعاوني هو كل ما هو مطلوب، فإن استخدام خيط يمكن أن يكون مبالغة.
أحد الفروق المهمة بين الخيوط والروتينات المشتركة هو أن الخيوط يتم جدولتها مسبقًا في حين أن الروتينات المشتركة لا يتم جدولتها مسبقًا. نظرًا لأنه يمكن إعادة جدولة الخيوط في أي لحظة ويمكن تنفيذها في وقت واحد، يجب أن تكون البرامج التي تستخدم الخيوط حذرة بشأن القفل . على النقيض من ذلك، نظرًا لأنه لا يمكن إعادة جدولة الروتينات المشتركة إلا في نقاط محددة في البرنامج ولا يتم تنفيذها في وقت واحد، يمكن للبرامج التي تستخدم الروتينات المشتركة غالبًا تجنب القفل تمامًا. يُستشهد بهذه الخاصية أيضًا كفائدة للبرمجة القائمة على الأحداث أو البرمجة غير المتزامنة.
نظرًا لأن الألياف مجدولة بشكل تعاوني، فإنها توفر قاعدة مثالية لتنفيذ الروتينات التعاونية أعلاه. [23] ومع ذلك، غالبًا ما يكون دعم النظام للألياف غير كافٍ مقارنة بدعم الخيوط.
ج
لتنفيذ الروتينات المشتركة للأغراض العامة، يجب الحصول على مكدس نداء ثانٍ ، وهي ميزة لا تدعمها لغة C بشكل مباشر . تتمثل إحدى الطرق الموثوقة (وإن كانت خاصة بالمنصة) لتحقيق ذلك في استخدام قدر صغير من التجميع المضمن للتلاعب صراحةً بمؤشر المكدس أثناء الإنشاء الأولي للروتين المشترك. هذا هو النهج الذي أوصى به توم داف في مناقشة حول مزاياه النسبية مقابل الطريقة المستخدمة بواسطة Protothreads . [24] [ مصدر غير أساسي مطلوب ] على الأنظمة الأساسية التي توفر نداء نظام POSIX sigaltstack، يمكن الحصول على مكدس نداء ثانٍ عن طريق استدعاء وظيفة Springboard من داخل معالج إشارة [25] [26] لتحقيق نفس الهدف في C المحمولة، على حساب بعض التعقيد الإضافي. قدمت مكتبات C المتوافقة مع POSIX أو Single Unix Specification (SUSv3) روتينات مثل getcontext و setcontext و makecontext و swapcontext ، ولكن تم إعلان هذه الوظائف عفا عليها الزمن في POSIX 1.2008. [27]
بمجرد الحصول على مكدس نداء ثانٍ باستخدام إحدى الطرق المذكورة أعلاه، يمكن بعد ذلك استخدام الدالتين setjmp وlongjmp في مكتبة C القياسية لتنفيذ التبديلات بين الروتينات الفرعية. تحفظ هذه الدالتان وتستعيدان، على التوالي، مؤشر المكدس ، وعداد البرنامج ، والسجلات المحفوظة بواسطة المستدعى ، وأي حالة داخلية أخرى كما هو مطلوب بواسطة واجهة برمجة التطبيقات الثنائية ، بحيث يؤدي العودة إلى روتين فرعي بعد الخضوع إلى استعادة جميع الحالات التي سيتم استعادتها عند العودة من استدعاء وظيفة. قد تحقق التنفيذات البسيطة، التي لا تعتمد على الدالتين setjmp وlongjmp، نفس النتيجة عبر كتلة صغيرة من التجميع المضمن الذي يبدل فقط مؤشر المكدس وعداد البرنامج، ويعطل جميع السجلات الأخرى. يمكن أن يكون هذا أسرع بشكل ملحوظ، حيث يجب على setjmp وlongjmp تخزين جميع السجلات التي قد تكون قيد الاستخدام وفقًا لواجهة برمجة التطبيقات الثنائية، في حين تسمح طريقة clobber للمترجم بتخزين (عن طريق الانسكاب إلى المكدس) فقط ما يعرف أنه قيد الاستخدام بالفعل.
بسبب عدم وجود دعم مباشر للغة، كتب العديد من المؤلفين مكتباتهم الخاصة للروتينات التعاونية التي تخفي التفاصيل المذكورة أعلاه. مكتبة libtask الخاصة بـ Russ Cox [28] هي مثال جيد لهذا النوع. تستخدم وظائف السياق إذا تم توفيرها بواسطة مكتبة C الأصلية؛ وإلا فإنها توفر تنفيذاتها الخاصة لـ ARM وPowerPC وSparc وx86. تشمل التنفيذات البارزة الأخرى libpcl و [29] coro و [30] lthread و [31] libCoroutine و [32] libconcurrency و [33] libcoro و [34] ribs2 و [35] libdill. و [36] libaco و [37] وlibco. [26]
بالإضافة إلى النهج العام المذكور أعلاه، تم إجراء عدة محاولات لتقريب البرامج الفرعية بلغة سي باستخدام مجموعات من البرامج الفرعية والماكرو. إن مساهمة سيمون تاتهام ، [38] المستندة إلى جهاز داف ، هي مثال بارز لهذا النوع، وهي الأساس لـ Protothreads وتنفيذات مماثلة. [39] بالإضافة إلى اعتراضات داف، [24] تقدم تعليقات تاتهام تقييمًا صريحًا لقيود هذا النهج: "بقدر ما أعلم، هذه أسوأ قطعة من قرصنة سي التي شوهدت على الإطلاق في كود إنتاج جاد." [38] تتمثل العيوب الرئيسية لهذا التقريب في أنه في عدم الحفاظ على إطار مكدس منفصل لكل برنامج فرعي، لا يتم الحفاظ على المتغيرات المحلية عبر العائدات من الوظيفة، ومن غير الممكن الحصول على إدخالات متعددة للوظيفة، ولا يمكن الحصول على التحكم إلا من الروتين الأعلى مستوى. [24]
سي++
- قدمت لغة C++20 روتينات مشتركة موحدة كوظائف بدون مكدس يمكن تعليقها في منتصف التنفيذ واستئنافها في وقت لاحق. يتم تخزين حالة التعليق للروتين المشترك على الكومة. [40] تنفيذ هذا المعيار مستمر، حيث تدعم مُجمِّعات G++ وMSVC حاليًا الروتينات المشتركة القياسية بالكامل في الإصدارات الأخيرة. [41]
- concurrencpp - مكتبة C++20 توفر دعمًا خارجيًا لبرامج C++20 الفرعية، في شكل مهام قابلة للانتظار ومنفذين يقومون بتشغيلها.
- Boost.Coroutine - تم إنشاؤه بواسطة Oliver Kowalke، وهو عبارة عن مكتبة روتينات مشتركة محمولة تم إصدارها رسميًا من Boost منذ الإصدار 1.53. تعتمد المكتبة على Boost.Context وتدعم ARM وMIPS وPowerPC وSPARC وX86 على POSIX وMac OS X وWindows.
- Boost.Coroutine2 - تم إنشاؤه أيضًا بواسطة Oliver Kowalke، وهو عبارة عن مكتبة روتينات مشتركة محمولة حديثة منذ إصدار Boost 1.59. تستفيد من ميزات C++11، لكنها تزيل دعم الروتينات المشتركة المتماثلة.
- Mordor - في عام 2010، قامت شركة Mozy بفتح مكتبة C++ مفتوحة المصدر لتنفيذ البرامج الفرعية، مع التركيز على استخدامها لتلخيص عمليات الإدخال والإخراج غير المتزامنة إلى نموذج تسلسلي أكثر دراية. [42]
- CO2 - روتين تعاوني بدون مكدس يعتمد على حيل المعالج المسبق C++ ، مما يوفر محاكاة الانتظار/العائد.
- ScummVM - ينفذ مشروع ScummVM إصدارًا خفيف الوزن من الروتينات التعاونية الخالية من المكدس استنادًا إلى مقال Simon Tatham.
- tonbit::coroutine - تنفيذ روتيني غير متماثل .h واحد في C++11 عبر ucontext / fiber
- تم إطلاق الروتينات الفرعية في Clang في مايو 2017، مع استمرار تنفيذ libc++. [43]
- إيل بواسطة Docker
- oatpp-coroutines - روتينات فرعية بدون تكديس مع جدولة مصممة لعمليات الإدخال/الإخراج عالية التزامن. تم استخدامها في تجربة اتصالات WebSocket التي بلغت 5 ملايين بواسطة Oat++. جزء من إطار عمل الويب Oat++.
سي شارب
أضافت لغة C# 2.0 وظيفة شبه روتينية ( مولد ) من خلال نمط التكرار والكلمة yieldالأساسية. [44] [45] تتضمن لغة C# 5.0 دعمًا لقواعد اللغة await . بالإضافة إلى ذلك:
- يوفر إطار عمل MindTouch Dream REST تنفيذًا للروتينات التعاونية استنادًا إلى نمط التكرار C# 2.0.
- يستخدم إطار عمل أنماط الشاشة Caliburn ( تم أرشفته في 2013-01-19 على archive.today ) لـ WPF معاودات C# 2.0 لتسهيل برمجة واجهة المستخدم، وخاصة في السيناريوهات غير المتزامنة.
- تطبق مكتبة Power Threading (المؤرشفة 2010-03-24 على Wayback Machine ) بواسطة Jeffrey Richter AsyncEnumerator الذي يوفر نموذج برمجة غير متزامن مبسط باستخدام روتينات مشتركة تعتمد على المتكرر.
- يقوم محرك اللعبة Unity بتنفيذ الروتينات التعاونية.
- يوفر مشروع Servelat Pieces الذي صممه Yevhen Bobrov مزامنة شفافة لخدمات Silverlight WCF والقدرة على استدعاء أي طريقة متزامنة بشكل غير متزامن. يعتمد التنفيذ على كتل Coroutines iterator وC# iterator في Caliburn.
- StreamThreads هي مكتبة روتينية مشتركة مفتوحة المصدر وخفيفة الوزن بلغة C# تعتمد على أساليب تمديد التكرار. وهي تدعم معالجة الأخطاء وقيم الإرجاع.
كلوجور
Cloroutine هي مكتبة تابعة لجهة خارجية توفر الدعم للروتينات الفرعية غير المكدسة في Clojure . يتم تنفيذها كوحدة ماكرو، وتقسيم كتلة تعليمات برمجية عشوائية بشكل ثابت على مكالمات متغيرات عشوائية وإصدار الروتين الفرعي كدالة حالة.
د
ينفذ D روتينات تعاونية كفئة مكتبة قياسية. يجعل مولد Fiber A من السهل عرض وظيفة الألياف كنطاق إدخال ، مما يجعل أي ألياف متوافقة مع خوارزميات النطاق الموجودة.
يذهب
تحتوي لغة Go على مفهوم مدمج لـ " goroutines "، وهي عمليات خفيفة الوزن ومستقلة يتم إدارتها بواسطة وقت تشغيل Go. يمكن بدء تشغيل goroutine جديد باستخدام الكلمة الأساسية "go". يحتوي كل goroutine على مكدس متغير الحجم يمكن توسيعه حسب الحاجة. تتواصل goroutines بشكل عام باستخدام القنوات المضمنة في Go. [46] [47] [48] [49] ومع ذلك، فإن goroutines ليست روتينات مشتركة (على سبيل المثال، لا تستمر البيانات المحلية بين المكالمات المتعاقبة). [50]
جافا
توجد عدة تطبيقات للروتينات التعاونية في Java . وعلى الرغم من القيود التي تفرضها تجريدات Java، فإن JVM لا تستبعد الاحتمالية. [51] هناك أربع طرق عامة مستخدمة، لكن اثنتين منها تكسران قابلية نقل البايت كود بين JVMs المتوافقة مع المعايير.
- تم تعديل JVMs. من الممكن إنشاء JVM مُرقعة لدعم البرامج الفرعية بشكل أكثر أصالة. تم إنشاء تصحيحات لـ Da Vinci JVM. [52]
- تم تعديل البايت كود. يمكن تنفيذ وظيفة الروتين الفرعي عن طريق إعادة كتابة البايت كود العادي في Java، إما أثناء التنفيذ أو في وقت التجميع. تتضمن مجموعات الأدوات Javaflow وJava Coroutines وCoroutines.
- آليات JNI الخاصة بالمنصة. تستخدم هذه الآليات أساليب JNI المطبقة في نظام التشغيل أو مكتبات C لتوفير الوظيفة لـ JVM. [ بحاجة لمصدر ]
- تجريدات الخيوط. قد تكون مكتبات الروتينات الفرعية التي يتم تنفيذها باستخدام الخيوط ثقيلة الوزن، على الرغم من أن الأداء سيختلف بناءً على تنفيذ الخيوط في JVM.
جافا سكريبت
منذ ECMAScript 2015 ، أصبح JavaScript يدعم المولدات ، وهي حالة خاصة من البرامج الفرعية. [53]
كوتلين
تطبق Kotlin الروتينات التعاونية كجزء من مكتبة الطرف الأول.
لوا
لقد دعمت لغة Lua البرامج الفرعية غير المتماثلة المكدسة من الدرجة الأولى منذ الإصدار 5.0 (2003)، [54] في البرنامج الفرعي للمكتبة القياسية . [55] [56]
نموذج 2
Modula-2 كما هو محدد بواسطة Wirth ينفذ الروتينات التعاونية كجزء من مكتبة SYSTEM القياسية.
يقوم الإجراء NEWPROCESS() بملء السياق المعطى لكتلة التعليمات البرمجية ومساحة للمكدس كمعلمات، ويقوم الإجراء TRANSFER() بنقل التحكم إلى روتين فرعي معطى لسياق الروتين الفرعي كمعلمة له.
كثرة الوحيدات
يدعم Mono Common Language Runtime الاستمرارية، [ 57 ] والتي يمكن من خلالها بناء الروتينات الفرعية.
إطار عمل .NET
أثناء تطوير .NET Framework 2.0، قامت Microsoft بتوسيع تصميم واجهات برمجة تطبيقات استضافة Common Language Runtime (CLR) للتعامل مع الجدولة القائمة على الألياف مع التركيز على استخدامها في وضع الألياف لخادم SQL. [58] قبل الإصدار، تمت إزالة دعم خطاف تبديل المهام ICLRTask::SwitchOut بسبب قيود الوقت. [59] وبالتالي، فإن استخدام واجهة برمجة تطبيقات الألياف لتبديل المهام ليس خيارًا قابلاً للتطبيق حاليًا في .NET Framework. [ يحتاج إلى تحديث ]
أوكامل
يدعم OCaml البرامج الفرعية من خلال Threadوحدته. [60] توفر هذه البرامج الفرعية التزامن دون التوازي، ويتم جدولتها مسبقًا على خيط نظام تشغيل واحد. منذ OCaml 5.0، أصبحت الخيوط الخضراء متاحة أيضًا؛ يتم توفيرها بواسطة وحدات مختلفة.
بيرل
- كورو
يتم تنفيذ الروتينات الفرعية بشكل أصلي في جميع واجهات Raku الخلفية. [61]
بي اتش بي
- ألياف أصلية منذ PHP 8.1
- أمفب
- افتح السويل
- تم تنفيذ الروتين الفرعي بطريقة تشبه وظائف Python ، وبعض Go ، والعديد من الأمثلة التي توضح أن الكود تم تحويله بنفس عدد الأسطر والسلوك.
بايثون
- ينفذ Python 2.5 دعمًا أفضل لوظائف تشبه وظائف الروتين التعاوني، استنادًا إلى المولدات الممتدة (PEP 342)
- يعمل Python 3.3 على تحسين هذه القدرة، من خلال دعم التفويض إلى مولد فرعي (PEP 380)
- يقدم Python 3.4 إطار عمل شامل للإدخال والإخراج غير المتزامن كما هو موحد في PEP 3156، والذي يتضمن برامج فرعية تستفيد من تفويض المولد الفرعي
- يقدم Python 3.5 دعمًا صريحًا للروتينات التعاونية ذات صيغة async/ await (PEP 0492).
- منذ Python 3.7، أصبحت async/await كلمات رئيسية محجوزة. [62]
- حدث صغير
- جرينليت
- حدث
- بايثون بدون مكدس
مضرب
يوفر Racket استمرارية أصلية، مع تنفيذ بسيط للروتينات الفرعية المتوفرة في كتالوج الحزم الرسمي. التنفيذ بواسطة S. De Gabrielle
روبي
- يدعم Ruby 1.9 البرامج الفرعية بشكل أصلي والتي يتم تنفيذها كألياف، وهي عبارة عن برامج فرعية شبه فرعية. [63]
- تنفيذ مارك دي شيمايكر
- يدعم Ruby 2.5 والإصدارات الأحدث البرامج الفرعية بشكل أصلي والتي يتم تنفيذها كألياف
- تنفيذ بواسطة توماس دبليو برانسون
مخطط
نظرًا لأن Scheme يوفر دعمًا كاملاً للاستمراريات، فإن تنفيذ البرامج الفرعية أمر تافه تقريبًا، ولا يتطلب سوى الحفاظ على قائمة انتظار للاستمراريات.
محادثة قصيرة
نظرًا لأن مجموعة التنفيذ في معظم بيئات Smalltalk تعتبر مواطنًا من الدرجة الأولى، فمن الممكن تنفيذ البرامج الفرعية دون الحاجة إلى دعم مكتبة إضافية أو آلة افتراضية.
لغة أوامر الأدوات (Tcl)
منذ الإصدار 8.6، تدعم لغة أوامر الأدوات البرامج الفرعية في اللغة الأساسية. [64]
فالا
تطبق Vala دعمًا أصليًا للروتينات الفرعية. وهي مصممة للاستخدام مع حلقة Gtk الرئيسية، ولكن يمكن استخدامها بمفردها إذا تم توخي الحذر لضمان عدم الحاجة إلى استدعاء معاودة الاتصال النهائية قبل القيام، على الأقل، بـ yield واحد.
لغات التجميع
غالبًا ما توفر لغات التجميع المعتمدة على الآلة طرقًا مباشرة لتنفيذ الروتينات التعاونية. على سبيل المثال، في لغة التجميع MACRO-11 ، وهي لغة التجميع لعائلة أجهزة الكمبيوتر الصغيرة PDP-11 ، يتم تنفيذ التبديل "الكلاسيكي" للروتين التعاوني بواسطة التعليمات "JSR PC,@(SP)+"، والتي تقفز إلى العنوان المنبثق من المكدس وتدفع عنوان التعليمات الحالي ( أي عنوان التعليمات التالي ) إلى المكدس. في VAXen (في VAX MACRO )، التعليمات المماثلة هي "JSB @(SP)+". حتى في Motorola 6809، توجد التعليمات "JSR [,S++]"؛ لاحظ "++"، حيث يتم إخراج 2 بايت (من العنوان) من المكدس. تُستخدم هذه التعليمات كثيرًا في Assist 09 (القياسي) "monitor".
انظر أيضا
- غير متزامن/انتظار
- خط الأنابيب ، نوع من البرامج الفرعية المستخدمة للتواصل بين البرامج [65]
- Protothreads ، تنفيذ خيوط خفيفة الوزن بدون تكديس باستخدام آلية تشبه الروتين الفرعي
مراجع
- ^ "كيف يعمل async/await في Python 3.5؟". Tall, Snarky Canadian . 2016-02-11 . تم الاسترجاع في 2023-01-10 .
- ^ Knuth, Donald Ervin (1997). Fundamental Algorithms (PDF) . The Art of Computer Programming. المجلد 1 (الطبعة الثالثة). Addison-Wesley. القسم 1.4.5: التاريخ والمراجع، ص 229. ISBN 978-0-201-89683-1. مؤرشف من الأصل (PDF) في 2019-10-21.
- ^ كونواي، ميلفين إي. (يوليو 1963). "تصميم مُجمِّع مخططات انتقالية قابلة للفصل" (PDF) . اتصالات ACM . 6 (7). ACM: 396–408. doi :10.1145/366663.366704. ISSN 0001-0782. S2CID 10559786 – عبر مكتبة ACM الرقمية.
- ^ مارلين، كريستوفر (1980). الروتينات الفرعية: منهجية برمجة، تصميم لغة وتنفيذ . سبرينغر. رقم ISBN 3-540-10256-6.
- ^ آنا لوسيا دي مورا؛ روبرتو ييروسالمشي (2009). "إعادة النظر في الروتينات الفرعية". معاملات ACM للغات البرمجة والأنظمة . 31 (2): 1-31. CiteSeerX 10.1.1.58.4017 . doi :10.1145/1462166.1462167. S2CID 9918449.
- ^ ab Knuth, Donald Ervin (1997). الخوارزميات الأساسية . فن برمجة الكمبيوتر. المجلد 1 (الطبعة الثالثة). Addison-Wesley. القسم 1.4.2: الروتينات الفرعية، ص 193-200. ISBN 978-0-201-89683-1.
- ^ بيرليس، آلان جيه. (سبتمبر 1982). "العبارات المختصرة عن البرمجة". إشعارات ACM SIGPLAN . 17 (9): 7–13. doi : 10.1145/947955.1083808 . S2CID 20512767. مؤرشف من الأصل في 17 يناير 1999.
6. التناظر هو مفهوم يقلل من التعقيد (تتضمن البرامج الفرعية البرامج الفرعية)؛ ابحث عنه في كل مكان
- ^ أنتوني رالستون (2000). موسوعة علوم الكمبيوتر. مجموعة نيتشر للنشر. رقم ISBN 978-1-56159-248-7تم الاسترجاع بتاريخ 11 مايو 2013 .
- ^ انظر على سبيل المثال مرجع لغة بايثون
"https://docs.python.org/reference/expressions.html#yieldexpr 5.2.10. Yield expressions]":
"كل هذا يجعل وظائف المولد مشابهة تمامًا للروتينات التعاونية؛ فهي تنتج عدة مرات، ولديها أكثر من نقطة دخول ويمكن تعليق تنفيذها. والفرق الوحيد هو أن وظيفة المولد لا يمكنها التحكم في المكان الذي يجب أن يستمر فيه التنفيذ بعد إنتاجها؛ يتم نقل التحكم دائمًا إلى المتصل بالمولد." - ^ ميرتز، ديفيد (1 يوليو 2002). "آلات الحالة القائمة على المولدات". بايثون الساحرة . IBM developerWorks. مؤرشف من الأصل في 28 فبراير 2009. تم الاسترجاع في 2 فبراير 2011 .
- ^ "روتين فرعي: روتين فرعي آمن للأنواع باستخدام أنواع جلسات خفيفة الوزن".
- ^ "الروتينات المشتركة في Haskell".
- ^ "وحدة الروتينات الفرعية (coroutines.hhf)". دليل مكتبة HLA القياسية .
- ^ "جديد في JavaScript 1.7". مؤرشف من الأصل في 2009-03-08 . تم الاسترجاع 2018-06-18 .
- ^ "دليل جوليا - تدفق التحكم - المهام (المعروفة أيضًا باسم الروتينات الفرعية)".
- ^ "ما الجديد في Kotlin 1.1".
- ^ "دليل مرجعي لـ Lua 5.2". www.lua.org .
- ^ "Python async/await Tutorial". Stack Abuse . 17 ديسمبر 2015.
- ^ "8. العبارات المركبة — توثيق Python 3.8.0". docs.python.org .
- ^ "التجميع و/أو الروتينات الفرعية". 2012-12-19.
- ^ Dahl, OJ; Hoare, CAR, eds. (1972). "Hierarchical Program Structures". Structured Programming . London, UK: Academic Press. pp. 175–220. ISBN 978-0-12-200550-3.
- ^ McCartney, J. "إعادة التفكير في لغة برمجة الموسيقى الحاسوبية: SuperCollider". مجلة الموسيقى الحاسوبية، 26(4):61-68. مطبعة معهد ماساتشوستس للتكنولوجيا، 2002.
- ^ تنفيذ الروتينات الفرعية لـ .NET عن طريق تغليف واجهة برمجة تطبيقات الألياف غير المُدارة محفوظ في 2008-09-07 على موقع Wayback Machine ، أجاي شانكار، مجلة MSDN
- ^ abc "الروتينات الفرعية في لغة C – brainwagon". 5 مارس 2005.
- ^ Ralf S. Engelschall (18–23 June 2000). Portable Multithreading – The Signal Stack Trick For User-Space Thread Creation (PS) . المؤتمر الفني السنوي لـ USENIX. سان دييغو، الولايات المتحدة الأمريكية.
- ^ من "libco" .code.byuu.org .[ رابط ميت دائم ]
- ^ "getcontext(3) - صفحة دليل Linux". man7.org .
- ^ http://swtch.com/libtask/ - مكتبة libtask coroutine الخاصة بـ Russ Cox لـ FreeBSD وLinux وMac OS X وSunOS
- ^ مكتبة Coroutine المحمولة - مكتبة C تستخدم مرافق POSIX/SUSv3
- ^ http://www.goron.de/~froese/coro/ محفوظ في 10 يناير 2006 على موقع Wayback Machine - مكتبة coro الخاصة بـ Edgar Toernig لـ x86 وLinux وFreeBSD
- ^ https://github.com/halayli/lthread - lthread هي مكتبة روتينية متعددة النواة/متعددة الخيوط مكتوبة بلغة C
- ^ "libcoroutine: A portable coroutine implementation". مؤرشف من الأصل في 2019-11-12 . تم الاسترجاع في 2013-09-06 .لـ FreeBSD وLinux وOS X PPC وx86 وSunOS وSymbian وغيرها
- ^ "libconcurrency - مكتبة متزامنة قابلة للتطوير لـ C".مكتبة C بسيطة لبرامج التبديل المحمولة
- ^ "libcoro: مكتبة C التي تنفذ الروتينات التعاونية (تعدد المهام التعاوني) بطريقة محمولة".تم استخدامه كأساس لوحدة Coro Perl.
- ^ "RIBS (البنية التحتية القوية لأنظمة الواجهة الخلفية) الإصدار 2: aolarchive/ribs2". 13 أغسطس 2019 – عبر GitHub.
- ^ "libdill". libdill.org . مؤرشف من الأصل في 2019-12-02 . تم الاسترجاع 2019-10-21 .
- ^ "مكتبة برامج فرعية غير متماثلة خفيفة الوزن وسريعة للغاية للغة C 💎 ⛅🚀⛅🌞: hnes/libaco". 21 أكتوبر 2019 - عبر GitHub.
- ^ من قبل سيمون تاتهام (2000). "الروتينات الفرعية في سي".
- ^ "تنفيذ روتينات فرعية بدون تكديس في C وC++: jsseldenthuis/coroutine". 18 مارس 2019 – عبر GitHub.
- ^ http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/n4680.pdf - المواصفات الفنية للروتينات الفرعية
- ^ https://en.cppreference.com/w/cpp/compiler_support#cpp20 - دعم المترجم الحالي للروتينات القياسية
- ^ http://mozy.com/blog/announcements/open-source-and-mozy-the-debut-of-mozy-code/ - المصدر المفتوح وموزي: ظهور موزي كود لأول مرة
- ^ https://twitter.com/eric01/status/867473461836263424 - EricWF: أصبحت البرامج الفرعية الآن في Clang Trunk! أعمل الآن على تنفيذ Libc++.
- ^ Wagner, Bill (11 نوفمبر 2021). "Iterators". توثيق C# . Microsoft – عبر Microsoft Learn.
- ^ Wagner, Bill (13 فبراير 2023). "تاريخ لغة C#". توثيق لغة C# . Microsoft . إصدار C# 2.0 – عبر Microsoft Learn.
- ^ "Goroutines - Effective Go". go.dev . تم الاسترجاع في 2022-11-28 .
- ^ "عبارات Go - مواصفات Go". go.dev . تم الاسترجاع في 2022-11-28 .
- ^ "Goroutines - جولة في Go". go.dev . تم الاسترجاع في 2022-11-28 .
- ^ "الأسئلة الشائعة (FAQ) - لغة برمجة Go". go.dev .
- ^ "Corotines for Go". swtch.com . تم الاسترجاع في 2024-10-24 .
- ^ لوكاس ستادلر (2009). "JVM Continuations" (PDF) . JVM Language Summit.
- ^ Remi Forax (19 نوفمبر 2009). "يا إلهي: JVM لديها روتين/استمرار/ألياف وما إلى ذلك". مؤرشف من الأصل في 19 مارس 2015.
- ^ "ECMAScript 6: ميزات جديدة: نظرة عامة ومقارنة - بروتوكول تكرار الدالة المولدة". es6-features.org . مؤرشف من الأصل في 18 مارس 2018. تم الاسترجاع في 19 مارس 2018 .
{{cite web}}:CS1 maint: عنوان URL غير مناسب ( الرابط ) - ^ "تاريخ إصدار Lua". Lua.org .
- ^ دي مورا، آنا لوسيا؛ رودريجيز، نويمي؛ ييروساميشي، روبرتو. “كوروتين في لوا” (PDF) . لوا.org . تم الاسترجاع 24 أبريل 2023 .
- ^ دي مورا، آنا لوسيا؛ رودريجيز، نويمي؛ إيروسالمشي، روبرتو (2004). "كوروتين في لوا". مجلة علوم الكمبيوتر العالمية . 10 (7): 901--924.
- ^ http://www.mono-project.com/Continuations استمراريات مونو
- ^ http://blogs.msdn.com/cbrumme/archive/2004/02/21/77595.aspx، كريس بروم، WebLog الخاص بـ cbrumme
- ^ kexugit (15 سبتمبر 2005). "وضع الألياف اختفى..." docs.microsoft.com . تم الاسترجاع في 2021-06-08 .
- ^ "مكتبة الخيوط".
- ^ "RFC #31".
- ^ "ما الجديد في Python 3.7" . تم الاسترجاع في 10 سبتمبر 2021 .
- ^ "semi-coroutines". مؤرشف من الأصل في 24 أكتوبر 2007.
- ^ "صفحة دليل الروتينات الفرعية - أوامر Tcl المضمنة". Tcl.tk . تم الاسترجاع في 2016-06-27 .
- ^ ريتشي، دينيس م. (1980). "تطور نظام تقاسم الوقت في يونكس". تصميم اللغة ومنهجية البرمجة. مذكرات محاضرات في علوم الكمبيوتر. المجلد 79. ص 25-35. doi :10.1007/3-540-09745-7_2. ISBN 978-3-540-09745-7. S2CID 571269. مؤرشف من الأصل في 2015-04-08 . تم الاسترجاع 2011-01-26 .
قراءة إضافية
- آنا لوسيا دي مورا؛ روبرتو ييروسالمشي (2004). "إعادة النظر في الروتينات الفرعية". معاملات ACM للغات البرمجة والأنظمة . 31 (2): 1-31. CiteSeerX 10.1.1.58.4017 . doi :10.1145/1462166.1462167. S2CID 9918449.
روابط خارجية
- مقدمة شاملة لـ C موجهة إلى البرامج الفرعية لـ Simon Tatham
- صفحة الروتينات الفرعية لبرنامج Softpanorama – تحتوي على روابط شاملة للروتينات الفرعية لبرنامج التجميع
