دروس الوحدة (3/5)
`تحديد`: تعدد القنوات
select ينتظر عمليات القنوات المتعددة في نفس الوقت.
إنها switch لتزامن Go: فهي تتيح لك التفاعل مع أول
قناة جاهزة بين العديد.
بناء الجملة
select {
case v := <-ch1:
fmt.Println("ch1:", v)
case v := <-ch2:
fmt.Println("ch2:", v)
case ch3 <- 99:
fmt.Println("inviato su ch3")
case <-time.After(time.Second):
fmt.Println("timeout")
default:
fmt.Println("nessuno è pronto")
}دلالات:
- يتم تقييم جميع الحالات. يتم اختيار حالة واحدة فقط من الحالات الجاهزة.
- إذا كانت هناك عدة حالات جاهزة، يكون الاختيار عشوائيًا زائفًا (بدون ترتيب).
- إذا لم تكن هناك حالة جاهزة: يتم حظر
selectحتى تصبح الحالة جاهزة. - إذا كان هناك
default: فسيتم تشغيله فورًا عندما لا تكون هناك حالة جاهزة (**حدد **غير محظور**).
نمط المهلة
select {
case res := <-fetch(url):
use(res)
case <-time.After(2 * time.Second):
log.Println("timeout: fetch troppo lento")
}time.After(d) تُرجع <-chan Time التي تنتج قيمة بعد d.
إنها الطريقة الكلاسيكية لربط الانتظار.
تحديد عدم الحظر بشكل افتراضي
select {
case msg := <-ch:
process(msg)
default:
// niente da fare, prosegui
}إنه "يستطلع" القناة دون حجبها. مفيد في مسارات التعليمات البرمجية التي يجب أن يظل مستجيبًا دون انتظار إلزامي.
نمط "تم القناة".
ادمج select مع قناة الإلغاء:
func worker(in <-chan Job, done <-chan struct{}) {
for {
select {
case j := <-in:
process(j)
case <-done:
return // chi gestisce done segnala lo shutdown
}
}
}close(done) من مشغلات المنسق case <-done في كل
روتين الانتظار: الإغلاق المنسق.
حلقة مع التحديد
for {
select {
case v := <-input:
if v == nil {
return
}
handle(v)
case <-time.After(5 * time.Second):
keepAlive()
case <-ctx.Done():
return
}
}نمط "حلقة الحدث" النموذجي للخوادم والعاملين.
قناة لا شيء كحالة "معطلة".
خدعة متقدمة: case <-ch مع ch == nil أبدًا
مختارة. يتيح لك "تعطيل" الحالة ديناميكيًا:
var in chan int = source()
for {
select {
case v, ok := <-in:
if !ok {
in = nil // disabilita questo case
continue
}
handle(v)
case <-ctx.Done():
return
}
}عندما يتم إغلاق in، أقوم بإلغائه: يستمر select في التعامل مع فقط
حالات أخرى.
جربه
تنفيذ تحديد مع حالتين تستقبلان من ch1 و ch2؛ طباعة أي واحد وصل أولا.
إظهار التلميح
بناء الجملة `select { case ...: ... }` بحالة واحدة لكل قناة.
الحل متاح بعد 3 من المحاولات
أضف حالة انتهاء المهلة إلى التحديد باستخدام time.After(time.Second).
إظهار التلميح
`time.After(d)` هي قناة تستقبل بعد d.
الحل متاح بعد 3 من المحاولات
ما الذي يجعل التحديد غير محظور؟
select { case v := <-ch: ... ??? }خلاصة
selectينتظر أول حالة جاهزة من بين العديد من عمليات القناة.- الاختيار العشوائي الزائف بين حالات جاهزة متعددة.
default→ تحديد غير محظور (الاقتراع).time.After(d)للمهلات (ضع في اعتبارك التسرب في الحلقات: استخدمcontext).- الأنماط: قناة منتهية، حلقة حدث، قناة صفرية لتعطيل الحالة.
- فارغ
select{}= كتلة أبدية: خطأ دائمًا تقريبًا.