Ana içeriğe geç
Modül 7 · Ders 3 ders 5Kurstaki 33/50~12 min
Modül dersleri (3/5)

'select': kanalların çoğullanması

select aynı anda birden fazla kanal işleminde bekler. Go eşzamanlılığının switch'sidir: ilkine tepki vermenizi sağlar birçok kanal arasında hazır.

Sözdizimi

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")
}

Anlambilim:

  • Tüm vakalar değerlendirilir; hazır vakalardan yalnızca biri seçilir.
  • Birden fazla vaka hazırsa seçim sözde rastgele olur (sıralama yok).
  • Hiçbir vaka hazır değilse: select, bir vaka hazır olana kadar bloke eder.
  • Eğer bir default varsa: hiçbir vaka hazır olmadığında hemen çalışır (engellenmeyen seçim).

Zaman aşımı modeli

Go
select {
case res := <-fetch(url):
    use(res)
case <-time.After(2 * time.Second):
    log.Println("timeout: fetch troppo lento")
}

time.After(d), d'den sonra bir değer üreten bir <-chan Time döndürür. Beklemeyi sınırlamanın klasik yoludur.

Varsayılan olarak engellemesiz seçim

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

Kanalı engellemeden "yoklar". Kod yollarında kullanışlıdır zorunlu olarak beklemeden yanıt vermeye devam etmelidir.

"Kanal tamamlandı" modeli

select'yi bir iptal kanalıyla birleştirin:

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
        }
    }
}

Koordinatörden gelen close(done) her durumda case <-done tetikler bekleme yordamı: koordineli kapatma.

Seçimle döngü

Go
for {
    select {
    case v := <-input:
        if v == nil {
            return
        }
        handle(v)
    case <-time.After(5 * time.Second):
        keepAlive()
    case <-ctx.Done():
        return
    }
}

Sunucular ve çalışanlar için tipik "olay döngüsü" modeli.

"Devre dışı" durum olarak sıfır kanal

Gelişmiş bir numara: ch == nil ile case <-ch asla değildir seçildi. Bir vakayı dinamik olarak "devre dışı bırakmanıza" olanak tanır:

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 kapatıldığında onu geçersiz kılıyorum: select yalnızca diğer durumlar.

Deneyin

Egzersiz#go.m7.l3.e1
Denemeler: 0Yükleniyor…

Ch1 ve ch2'den alan iki durumla bir seçim uygulayın; hangisinin önce geldiğini yazdırın.

Düzenleyici yükleniyor…
İpucu göster

Sözdizimi kanal başına bir büyük harfle `select { case ...: ... }'.

3 denemeden sonra çözüm mevcut

Egzersiz#go.m7.l3.e2
Denemeler: 0Yükleniyor…

time.After(time.Second) kullanarak seçime bir zaman aşımı durumu ekleyin.

Düzenleyici yükleniyor…
İpucu göster

'time.After(d)' d'den sonra alan bir kanaldır.

3 denemeden sonra çözüm mevcut

Quiz#go.m7.l3.e3
Hazır

Select'i engellemeyen yapan şey nedir?

Go
select { case v := <-ch: ... ??? }
Cevap seçenekleri

Özet

  • select çeşitli kanal işlemleri arasında ilk hazır durumu bekler.
  • Birden fazla hazır durum arasında sözde rastgele seçim.
  • default → engellemeyen seçim (yoklama).
  • Zaman aşımları için time.After(d) (döngülerdeki sızıntıya dikkat edin: context kullanın).
  • Desenler: bir durumu devre dışı bırakmak için yapılan kanal, olay döngüsü, sıfır kanal.
  • Boş select{} = sonsuz blok: neredeyse her zaman bir hata.