الإشارات في جولانج

Alasharat Fy Jwlanj



بصرف النظر عن التميمة الرائعة حقًا، فإن إحدى الميزات الأكثر عملية وقوة في لغة البرمجة Go هي دعمها للتزامن.

عندما يتعلق الأمر بالأداء والاستخدام الفعال للموارد المتاحة في الأنظمة الحديثة، فإن Go لا مثيل له. اسأل دوكر.

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







في هذا البرنامج التعليمي، سوف نستكشف طريقة عمل الإشارات وتنفيذها في لغة Go. سنبدأ بماهية الإشارات ثم نقدم أمثلة حول كيفية إنشائها واستخدامها في Go.



ما هي الإشارات؟

دعونا نبدأ بالأساسيات.



الإشارة هي آلية مزامنة قوية ومفيدة تحافظ على عدد وعمليتين:





  1. انتظار
  2. إشارة

في الإشارة، العدد هو في الأساس رقم يشير إلى عدد الموارد.

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



ومع ذلك، إذا وصل عدد الموارد إلى الصفر، فإن أي استدعاءات 'انتظار' لاحقة ستمنع أي إجراءات goroutines من المتابعة حتى تصبح الموارد متاحة.

بمجرد انتهاء goroutine من المهمة باستخدام المورد، تتولى عمليات 'Signal' مهمة زيادة العدد للإشارة إلى أن المورد متاح للحصول عليه بواسطة goroutine آخر.

قم بإنشاء إشارة في Go

في Go، يمكننا إنشاء إشارة باستخدام قناة مخزنة. يمكن للقناة المخزنة مؤقتًا ذات الحجم 'N' أن تعمل بمثابة إشارة ذات عدد 'N' من الموارد.

ألق نظرة على الكود التالي:

طَرد رئيسي
func رئيسي () {
إشارة := يصنع ( تشان البنية {}، 5 )
تأجيل يغلق ( إشارة )
}

في هذا المثال، قمنا بإنشاء قناة مخزنة مؤقتًا تسمى 'الإشارة' بحجم 5. وهذا يعني أنها تحتوي على خمسة موارد.

لتحرير مورد، يمكننا إرسال بنية فارغة إلى القناة.

للحصول على مورد، نستقبله فقط من القناة.

التحكم بالإشارة في الوصول إلى أحد الموارد

وبطبيعة الحال، عندما يتعلق الأمر بالعالم الحقيقي، فمن الصعب أن يكون لديك إشارة أساسية. أحد أدوار الإشارة هو التحكم في الموارد.

لنفترض أن لدينا عددًا محدودًا من الموارد التي تحتاج goroutines المتعددة إلى الوصول إليها بشكل متزامن.

للتحكم في عدد goroutines التي يمكنها الوصول إليها في وقت واحد، يمكننا استخدام الإشارة كما هو موضح في المثال التالي:

طَرد رئيسي
يستورد (
'إف إم تي'
'مزامنة'
func عامل ( بطاقة تعريف كثافة العمليات , إشارة تشان البنية {}) {
fmt . برينتف ( 'العامل %d ينتظر الحصول على تصريح ' , بطاقة تعريف )
< - إشارة
تأجيل func () {
fmt . برينتف ( 'لقد قام العامل %d بإصدار التصريح ' , بطاقة تعريف )
الإشارة < - البنية {}{}
}(
fmt . برينتف ( 'العامل %d يعمل ' , بطاقة تعريف )
}
func رئيسي () {
إشارة := يصنع ( تشان البنية {}، 5 )
ل أنا := 0 ; أنا < 5 ; أنا ++ {
الإشارة < - البنية {}{}
}
تأجيل يغلق ( إشارة )
كان مزامنة مجموعة العمل . انتظر المجموعة
ل أنا := 1 ; أنا < = 5 ; أنا ++ {
فريق العمل . يضيف ( 1 )
يذهب func ( بطاقة تعريف كثافة العمليات ) {
تأجيل فريق العمل . منتهي ()
عامل ( بطاقة تعريف , إشارة )
}( أنا )
}
فريق العمل . انتظر ()
}

في المثال الموضح، نعلن عن دالة عاملة تحاكي مهمة يتم تنفيذها بواسطة goroutine. تقبل الوظيفة معلمتين: معرف لتحديد العامل وإشارة وهي القناة التي تتحكم في الوصول إلى المورد.

في الدالة، لدينا عملية 'إرسال' إلى القناة والتي يُشار إليها بالإشارة <-. إذا كانت القناة فارغة، فسيقوم العامل بالحظر والانتظار. وينتظر حتى يتلقى مورداً من القناة.

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

يؤدي تشغيل الكود المحدد إلى إرجاع ما يلي:

عامل 1 ينتظر ل تصريح
عامل 4 ينتظر ل تصريح
عامل 4 يعمل
عامل 4 لقد أطلق التصريح
عامل 3 ينتظر ل تصريح
عامل 3 يعمل
عامل 1 يعمل
عامل 1 لقد أطلق التصريح
عامل 5 ينتظر ل تصريح
عامل 5 يعمل
عامل 5 لقد أطلق التصريح
عامل 3 لقد أطلق التصريح
عامل 2 ينتظر ل تصريح
عامل 2 يعمل
عامل 2 لقد أطلق التصريح

يُظهر هذا مثالًا جيدًا للغاية لإشارة تتحكم في الموارد المشتركة لعدة goroutines التي تحاول الوصول إلى الموارد واستخدامها بشكل متزامن.

خاتمة

في هذا البرنامج التعليمي، تعلمنا عن واحدة من أقوى التركيبات عندما يتعلق الأمر بالتزامن: الإشارة التي تستخدم القنوات في لغة البرمجة Go. كن حذرًا بشأن حالات الجمود كما هو الحال مع كل ما يتعلق بالتزامن.