Lompati ke konten utama
Modul 7 · Pelajaran 3 dari 533/50 dalam kursus~12 min
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

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

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: select diblokir hingga ada yang siap.
  • Jika ada default: langsung dijalankan ketika tidak ada case yang siap (non-blocking pilih).

Pola batas waktu

Go
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

Go
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:

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) dari koordinator memicu case <-done di setiap menunggu goroutine: shutdown terkoordinasi.

Ulangi dengan pilih

Go
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:

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

Ketika in ditutup, saya membatalkannya: select tetap hanya menangani kasus lainnya.

Cobalah

Latihan#go.m7.l3.e1
Upaya: 0Memuat…

Terapkan pemilihan dengan dua kasus yang diterima dari ch1 dan ch2; cetak mana yang lebih dulu sampai.

Memuat editor…
Tunjukkan petunjuk

Sintaks `select { case ...: ... }` dengan satu case per saluran.

Solusi tersedia setelah 3 upaya

Latihan#go.m7.l3.e2
Upaya: 0Memuat…

Tambahkan kasus batas waktu ke pilihan menggunakan time.After(time.Second).

Memuat editor…
Tunjukkan petunjuk

`time.After(d)` adalah saluran yang menerima setelah d.

Solusi tersedia setelah 3 upaya

Quiz#go.m7.l3.e3
Siap

Apa yang membuat pilihan menjadi non-pemblokiran?

Go
select { case v := <-ch: ... ??? }
Pilihan jawaban

Rekap

  • select menunggu 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: gunakan context).
  • Pola: saluran selesai, loop acara, saluran nihil untuk menonaktifkan kasus.
  • Kosong select{} = blok abadi: hampir selalu bug.