0Pricing
Go Academy · Pelajaran

Channel Berbuffer

Kapasitas, penutupan channel, dan range pada channel

Channel Berbuffer adalah pelajaran Go Academy gratis di CoddyKit. Ini adalah pelajaran 3 dari 4. Kamu bisa membaca pelajaran lengkapnya di bawah secara gratis — lalu praktikkan langsung di browser dengan editor kode bawaan dan tutor AI 24/7. Ini adalah bagian dari jalur belajar Go Academy, dan progresmu tersinkronisasi di web dan aplikasi CoddyKit. Kursus Go Academy mencakup 4 pelajaran total.

Apa Itu Saluran Berpenyangga?

saluran berpenyangga memiliki kapasitas — pengiriman tidak terblokir selama penyangga masih memiliki ruang. Saluran bertindak seperti antrean:

package main
import "fmt"

func main() {
    ch := make(chan int, 3)  // capacity 3

    ch <- 1  // does not block — buffer has room
    ch <- 2  // does not block
    ch <- 3  // does not block
    // ch <- 4  // would block — buffer full

    fmt.Println(<-ch) // 1
    fmt.Println(<-ch) // 2
    fmt.Println(<-ch) // 3
}

Saluran Berpenyangga sebagai Antrean

Saluran berpenyangga menerapkan antrean FIFO di antara goroutine:

package main
import ("fmt"; "sync")

func producer(ch chan<- int, wg *sync.WaitGroup) {
    defer wg.Done()
    for i := 1; i <= 5; i++ {
        ch <- i
        fmt.Printf("produced %d\n", i)
    }
}

func main() {
    ch := make(chan int, 2)  // buffer 2 — producer runs ahead
    var wg sync.WaitGroup
    wg.Add(1)
    go producer(ch, &wg)
    wg.Wait()
    close(ch)
    for v := range ch { fmt.Printf("consumed %d\n", v) }
}

len() dan cap() pada Saluran

Periksa ukuran dan kapasitas saat ini dari saluran berpenyangga:

package main
import "fmt"

func main() {
    ch := make(chan string, 5)
    ch <- "a"
    ch <- "b"
    ch <- "c"

    fmt.Println("cap:", cap(ch))  // 5
    fmt.Println("len:", len(ch))  // 3 — items currently buffered

    <-ch
    fmt.Println("len:", len(ch))  // 2
}

Memisahkan Producer dan Consumer

Penyangga memisahkan kecepatan producer dari consumer. Producer dapat berjalan lebih cepat sebesar ukuran penyangga sebelum terblokir:

package main
import ("fmt"; "sync"; "time")

func produce(ch chan<- int, wg *sync.WaitGroup) {
    defer wg.Done()
    for i := 0; i < 5; i++ {
        ch <- i
    }
}

func consume(ch <-chan int, wg *sync.WaitGroup) {
    defer wg.Done()
    for v := range ch {
        time.Sleep(10 * time.Millisecond)  // slower consumer
        fmt.Println("consumed:", v)
    }
}

func main() {
    ch := make(chan int, 3)
    var wg sync.WaitGroup
    wg.Add(2)
    go produce(ch, &wg)
    go consume(ch, &wg) // BUG: produce closes before consume sees all
    // In practice, coordinate close carefully
    fmt.Println("decoupled")
}

Semafor dengan Saluran Berpenyangga

Saluran berpenyangga berkapasitas N dapat membatasi jumlah goroutine konkuren menjadi N — semafor sederhana:

package main
import ("fmt"; "sync"; "time")

func main() {
    sem := make(chan struct{}, 3)  // max 3 concurrent
    var wg sync.WaitGroup

    for i := 0; i < 10; i++ {
        wg.Add(1)
        i := i
        go func() {
            defer wg.Done()
            sem <- struct{}{}    // acquire
            defer func() { <-sem }()  // release
            fmt.Printf("job %d running\n", i)
            time.Sleep(50 * time.Millisecond)
        }()
    }
    wg.Wait()
}

Menutup Saluran Berpenyangga

Menutup saluran berpenyangga memungkinkan penerima menguras nilai yang tersisa di dalam penyangga sebelum mendeteksi penutupan:

package main
import "fmt"

func main() {
    ch := make(chan int, 5)
    for i := 1; i <= 3; i++ { ch <- i }
    close(ch)

    // Drain all buffered values after close:
    for v := range ch {
        fmt.Println(v)  // 1, 2, 3
    }
    // range exits after channel closed and drained
}

Berpenyangga vs Tanpa Penyangga: Kapan Memilihnya

Panduan pemilihan:

  • Tanpa penyangga: serah terima sinkron yang terjamin, pengurutan ketat, sinkronisasi pertemuan
  • Berpenyangga: memisahkan kecepatan producer/consumer, mengurangi pemblokiran, menerapkan semafor, mengumpulkan N hasil
  • Jadikan tanpa penyangga sebagai pilihan bawaan — tambahkan penyangga hanya jika Anda dapat membenarkan ukurannya
  • Ukuran penyangga yang terlalu kecil → tetap menyebabkan pemblokiran; terlalu besar → menyembunyikan bug

Mengumpulkan Hasil dengan Saluran Berpenyangga

Gunakan saluran berpenyangga untuk mengumpulkan hasil dari goroutine paralel tanpa pemblokiran:

package main
import ("fmt"; "sync")

func square(n int) int { return n * n }

func main() {
    nums := []int{1, 2, 3, 4, 5}
    results := make(chan int, len(nums))  // buffer = goroutine count
    var wg sync.WaitGroup

    for _, n := range nums {
        wg.Add(1)
        n := n
        go func() {
            defer wg.Done()
            results <- square(n)
        }()
    }
    wg.Wait()
    close(results)

    for r := range results { fmt.Println(r) }
}

Kebocoran Goroutine dengan Penyangga Penuh

Jika penyangga penuh dan tidak ada pembaca, sender akan terblokir selamanya — menyebabkan kebocoran goroutine:

package main
import ("fmt"; "time"; "runtime")

func main() {
    ch := make(chan int, 2)
    // Start goroutine that fills buffer and then blocks
    go func() {
        ch <- 1
        ch <- 2
        ch <- 3  // blocks: buffer full, no receiver
        fmt.Println("never reached")
    }()
    time.Sleep(50 * time.Millisecond)
    fmt.Println("goroutines:", runtime.NumGoroutine()) // 2 — leaked
}

time.After sebagai Saluran Berpenyangga

time.After mengembalikan <-chan time.Time dengan penyangga berkapasitas 1. Lingkungan eksekusi mengirim ke sana setelah durasi berlalu, lalu objek tersebut dikumpulkan oleh pengumpul sampah:

package main
import ("fmt"; "time")

func doWithTimeout(work func() string) (string, bool) {
    result := make(chan string, 1)
    go func() { result <- work() }()
    select {
    case r := <-result:
        return r, true
    case <-time.After(100 * time.Millisecond):
        return "", false
    }
}

func main() {
    r, ok := doWithTimeout(func() string {
        time.Sleep(50 * time.Millisecond)
        return "done"
    })
    fmt.Println(r, ok)
}

Pemeriksaan Singkat

Apa yang terjadi ketika Anda mengirim ke saluran berpenyangga yang kapasitasnya sudah penuh?

Ringkasan: Saluran Berpenyangga

Ringkasan:

  • make(chan T, N) membuat saluran berpenyangga dengan kapasitas N
  • Pengiriman terblokir hanya ketika penyangga penuh; penerimaan terblokir hanya ketika penyangga kosong
  • len(ch) — jumlah elemen saat ini; cap(ch) — kapasitas
  • Gunakan untuk memisahkan producer/consumer, mengumpulkan hasil paralel, dan menerapkan semafor
  • Close memungkinkan pengurasan sebelum EOF; range ch menanganinya secara otomatis

Pertanyaan yang Sering Diajukan

Apakah pelajaran “Channel Berbuffer” gratis?

Ya — teks lengkap “Channel Berbuffer” gratis dibaca di sini di web. Untuk praktiknya secara interaktif (editor kode bawaan dan tutor AI 24/7) dan buka sisa kursus Go Academy, upgrade ke CoddyKit PRO. Kursus Go Academy mencakup 4 pelajaran total.

Apa yang akan aku pelajari di “Channel Berbuffer”?

Kapasitas, penutupan channel, dan range pada channel Kamu berlatih Go Academy dengan kode praktik yang langsung kamu jalankan di browser, dan tutor AI 24/7 menjawab pertanyaanmu saat kamu mengerjakan pelajaran ini.

Apakah aku perlu pengalaman untuk memulai Go Academy?

Tidak diperlukan pengalaman sebelumnya. Go Academy di CoddyKit dirancang untuk pemula hingga pelajar tingkat lanjut, jadi kamu bisa memulai di sini atau dari awal dan belajar sesuai kecepatan kamu sendiri. Ini adalah pelajaran 3 dari 4.

Berapa lama pelajaran “Channel Berbuffer” memakan waktu?

Sebagian besar pelajaran CoddyKit memakan waktu sekitar 5–10 menit. Setiap pelajaran ringkas dan interaktif, jadi kamu membuat kemajuan stabil dan melanjutkan dari tempat kamu tinggalkan di web dan aplikasi.

Bisakah aku menulis dan menjalankan kode dalam pelajaran Go Academy ini?

Ya. Setiap pelajaran Go Academy menyertakan editor kode bawaan, jadi kamu menulis dan menjalankan kode nyata langsung di browser dan mendapatkan umpan balik AI instan — tidak diperlukan penyiapan lokal.

Semua pelajaran dalam kursus ini

  1. Menjalankan Goroutine
  2. Channel Tanpa Buffer
  3. Channel Berbuffer
  4. Arah Channel dan Pola Pipeline
← Kembali ke Go Academy