שיעורי מודול (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; להדפיס איזה מהם הגיע ראשון.
הצג רמז
תחביר `בחר { case ...: ... }` עם מקרה אחד לכל ערוץ.
הפתרון זמין לאחר 3 ניסיונות
הוסף מקרה פסק זמן לבחירה באמצעות time.After(time.Second).
הצג רמז
`time.After(d)` הוא ערוץ שמקבל אחרי d.
הפתרון זמין לאחר 3 ניסיונות
מה הופך בחירה ללא חסימה?
select { case v := <-ch: ... ??? }לְסַכֵּם
selectמחכה למקרה המוכן הראשון מבין מספר פעולות ערוץ.- בחירה פסאודו אקראית בין מספר מקרים מוכנים.
default→ בחירה לא חוסמת (סקר).time.After(d)לתקופות זמן קצובות (שים לב לדליפה בלולאות: השתמש ב-context).- דפוסים: ערוץ בוצע, לולאת אירועים, ערוץ אפס כדי להשבית מקרה.
- ריק
select{}= חסימה נצחית: כמעט תמיד באג.