← Kembali ke kursus
Pelajaran kursus · Go
Pelajaran 56

Concurrency patterns: pipeline & cancellation

Rangkai tahap goroutine dan batalkan lewat context.

Pahami konsepnya

Pipeline adalah goroutine-goroutine yang terhubung channel: tahap pertama MEMBUAT data (generator), tahap-tahap berikut MENGOLAH dan meneruskan hasilnya lewat channel keluaran. Tiap tahap berjalan bersamaan — sambil satu tahap menghitung, yang lain sudah menyiapkan berikutnya. Kunci polanya: setiap tahap menutup channel keluarannya setelah selesai, dan for range di hilir otomatis berhenti.

Fan-in/fan-out memperbanyak jalur: beberapa tahap pekerja yang SAMA membaca dari satu channel input (fan-out — memparalelkan kerja), hasilnya digabung ke satu channel (fan-in). Dengan begitu pekerjaan lambat dibagi ke semua core tanpa mengubah bentuk kodenya.

Pembatalan elegan lewat context.Context: context.WithCancel membuat channel Done yang tertutup saat cancel dipanggil. Setiap tahap memilih antara channel kerja dan ctx.Done — begitu sinyal pembatalan tiba, seluruh pipeline angkat kaki dengan rapi. Varian WithTimeout memasang pembatalan otomatis berbasis waktu; pola ini wajib di API modern Go.

Coba contoh kode

package main

import "fmt"

func generator(angka ...int) <-chan int {
    keluar := make(chan int)
    go func() {
        defer close(keluar)
        for _, n := range angka {
            keluar <- n
        }
    }()
    return keluar
}

func kuadrat(masuk <-chan int) <-chan int {
    keluar := make(chan int)
    go func() {
        defer close(keluar)
        for n := range masuk {
            keluar <- n * n
        }
    }()
    return keluar
}

func main() {
    for hasil := range kuadrat(generator(1, 2, 3, 4)) {
        fmt.Println(hasil) // 1 4 9 16
    }
}

Dua tahap terangkai: generator mengirim 1-4 lalu menutup; kuadrat menerima lewat range, mengalikan, meneruskan, lalu ikut menutup. main hanya membaca hasil akhir — penutupan berantai membuat seluruh pipeline mati dengan rapi setelah data habis. Tanda panah pada tipe (<-chan) membatasi channel jadi hanya-keluar: konsumen tak bisa mengirim balik.

Pembatalan dengan context

func kerja(ctx context.Context) <-chan int {
    keluar := make(chan int)
    go func() {
        defer close(keluar)
        for i := 1; ; i++ {
            select {
            case <-ctx.Done():
                return // sinyal batal: keluar rapi
            case keluar <- i:
            }
        }
    }()
    return keluar
}

func main() {
    ctx, cancel := context.WithCancel(context.Background())
    hasil := kerja(ctx)

    fmt.Println(<-hasil) // 1
    fmt.Println(<-hasil) // 2
    cancel()             // cukup: hentikan generator
}

select menjunjung dua kemungkinan: kirim nilai berikutnya, atau berhenti saat ctx.Done tertutup. cancel() menutup Done seketika dan generator pulang — goroutine tidak menggantung menunggu konsumen yang sudah pergi. context.WithTimeout(ctx, 2*time.Second) memakai bentuk yang sama dengan alarm otomatis.

Latihan singkat

Uji: sambung pipeline filter-genap → kuadrat, terima tiga hasil lalu batalkan — harus `4`, `16`, `36`, `selesai` (empat baris).