דילוג לתוכן המרכזי
מודול 7 · שיעור 3 מתוך 533/50 בקורס~12 min
שיעורי מודול (3/5)

'בחר': ריבוי ערוצים

select ממתין לפעולות מרובות ערוצים בו-זמנית. זה switch של בו-זמנית Go: זה מאפשר לך להגיב לראשון ערוץ מוכן מבין רבים.

תַחבִּיר

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: הוא פועל מיד כשאף מקרה לא מוכן (לא חוסם בחר).

דפוס פסק זמן

Go
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. זו הדרך הקלאסית לכבול את ההמתנה.

בחירה לא חוסמת עם ברירת מחדל

Go
select {
case msg := <-ch:
    process(msg)
default:
    // niente da fare, prosegui
}

זה "סוקר" את הערוץ בלי לחסום. שימושי בנתיבי קוד זה חייב להישאר מגיב מבלי להמתין חובה.

דפוס "ערוץ בוצע".

שלב את select עם ערוץ ביטול:

Go
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 בכל מחכה גורוטינה: כיבוי מתואם.

לולאה עם בחירה

Go
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 הוא אף פעם נבחר. זה מאפשר לך "לבטל" מקרה דינמי:

Go
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 ממשיך לטפל רק ב- מקרים אחרים.

נסה את זה

פעילות גופנית#go.m7.l3.e1
ניסיונות: 0טוען...

יישם בחירה עם שני מקרים שמקבלים מ-ch1 ו-ch2; להדפיס איזה מהם הגיע ראשון.

טוען עורך...
הצג רמז

תחביר `בחר { case ...: ... }` עם מקרה אחד לכל ערוץ.

הפתרון זמין לאחר 3 ניסיונות

פעילות גופנית#go.m7.l3.e2
ניסיונות: 0טוען...

הוסף מקרה פסק זמן לבחירה באמצעות time.After(time.Second).

טוען עורך...
הצג רמז

`time.After(d)` הוא ערוץ שמקבל אחרי d.

הפתרון זמין לאחר 3 ניסיונות

Quiz#go.m7.l3.e3
מוכן

מה הופך בחירה ללא חסימה?

Go
select { case v := <-ch: ... ??? }
אפשרויות תשובה

לְסַכֵּם

  • select מחכה למקרה המוכן הראשון מבין מספר פעולות ערוץ.
  • בחירה פסאודו אקראית בין מספר מקרים מוכנים.
  • default → בחירה לא חוסמת (סקר).
  • time.After(d) לתקופות זמן קצובות (שים לב לדליפה בלולאות: השתמש ב-context).
  • דפוסים: ערוץ בוצע, לולאת אירועים, ערוץ אפס כדי להשבית מקרה.
  • ריק select{} = חסימה נצחית: כמעט תמיד באג.