Pelajaran modul (3/5)
`pilih`: saluran multiplexing
select menunggu beberapa operasi saluran secara bersamaan.
Ini adalah switch dari konkurensi Go: ini memungkinkan Anda bereaksi terhadap yang pertama
saluran siap di antara banyak.
Sintaksis
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")
}Semantik:
- Semua kasus dievaluasi; hanya satu dari kasus siap yang dipilih.
- Jika beberapa case ready, pilihannya pseudo-random (tidak bisa pesan).
- Jika tidak ada kasing yang siap:
selectdiblokir hingga ada yang siap. - Jika ada
default: langsung dijalankan ketika tidak ada case yang siap (non-blocking pilih).
Pola batas waktu
select {
case res := <-fetch(url):
use(res)
case <-time.After(2 * time.Second):
log.Println("timeout: fetch troppo lento")
}time.After(d) mengembalikan <-chan Time yang menghasilkan nilai setelah d.
Ini adalah cara klasik untuk mengakhiri penantian.
Pilih non-pemblokiran dengan default
select {
case msg := <-ch:
process(msg)
default:
// niente da fare, prosegui
}Ini "melakukan polling" saluran tanpa memblokir. Berguna dalam jalur kode itu harus tetap tanggap tanpa wajib menunggu.
Pola "Saluran selesai".
Gabungkan select dengan saluran pembatalan:
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) dari koordinator memicu case <-done di setiap
menunggu goroutine: shutdown terkoordinasi.
Ulangi dengan pilih
for {
select {
case v := <-input:
if v == nil {
return
}
handle(v)
case <-time.After(5 * time.Second):
keepAlive()
case <-ctx.Done():
return
}
}Pola "event loop" yang khas untuk server dan pekerja.
Saluran nihil sebagai kasus "dinonaktifkan".
Trik tingkat lanjut: case <-ch dengan ch == nil tidak pernah
dipilih. Ini memungkinkan Anda "menonaktifkan" suatu kasus secara dinamis:
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
}
}Ketika in ditutup, saya membatalkannya: select tetap hanya menangani
kasus lainnya.
Cobalah
Terapkan pemilihan dengan dua kasus yang diterima dari ch1 dan ch2; cetak mana yang lebih dulu sampai.
Tunjukkan petunjuk
Sintaks `select { case ...: ... }` dengan satu case per saluran.
Solusi tersedia setelah 3 upaya
Tambahkan kasus batas waktu ke pilihan menggunakan time.After(time.Second).
Tunjukkan petunjuk
`time.After(d)` adalah saluran yang menerima setelah d.
Solusi tersedia setelah 3 upaya
Apa yang membuat pilihan menjadi non-pemblokiran?
select { case v := <-ch: ... ??? }Rekap
selectmenunggu kasus siap pertama di antara beberapa operasi saluran.- Pilihan acak semu di antara beberapa kasus siap pakai.
default→ pemilihan tanpa pemblokiran (polling).time.After(d)untuk batas waktu (perhatikan kebocoran dalam loop: gunakancontext).- Pola: saluran selesai, loop acara, saluran nihil untuk menonaktifkan kasus.
- Kosong
select{}= blok abadi: hampir selalu bug.