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
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
defaultvarsa: hiçbir vaka hazır olmadığında hemen çalışır (engellenmeyen seçim).
Zaman aşımı modeli
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
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:
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ü
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:
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
Ch1 ve ch2'den alan iki durumla bir seçim uygulayın; hangisinin önce geldiğini yazdırın.
İpucu göster
Sözdizimi kanal başına bir büyük harfle `select { case ...: ... }'.
3 denemeden sonra çözüm mevcut
time.After(time.Second) kullanarak seçime bir zaman aşımı durumu ekleyin.
İpucu göster
'time.After(d)' d'den sonra alan bir kanaldır.
3 denemeden sonra çözüm mevcut
Select'i engellemeyen yapan şey nedir?
select { case v := <-ch: ... ??? }Ö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:contextkullanı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.