Skip to content
Santekno.com | Tech Tutorials and Trends
ID
📖 0%
20 May 2026 · 5 mnt baca ·Artikel 6 / 12
Go

Goroutine dan Channel: Concurrency di Go untuk Pemula

Goroutine adalah superpower Go. Pelajari cara membuat goroutine, channel, dan pattern worker pool dalam 15 menit — lengkap dengan contoh kode yang bisa langsung dijalankan.

IH
Ihsan Arif
Penulis di Santekno · Backend Engineer

Pernah bayangkan server yang melayani ribuan request bersamaan tanpa harus kelola thread pool sendiri? Itulah yang goroutine bisa lakukan. Di artikel ini kamu akan belajar goroutine dan channel dari nol — tidak perlu background concurrency sebelumnya.

Apa itu Goroutine?

Goroutine adalah lightweight thread yang dikelola Go runtime, bukan OS. Membuat goroutine baru hanya butuh 2 KB stack awal — bandingkan dengan OS thread yang butuh 1–8 MB.

Karena itu, kamu bisa menjalankan ribuan goroutine bersamaan tanpa kehabisan memori. Ini bukan exaggeration — aplikasi Go production sering memiliki ratusan ribu goroutine aktif sekaligus.

Perbandingan Goroutine vs OS Thread

GoroutineOS Thread
Stack awal2 KB1–8 MB
Switching cost~200 ns~1 μs
Managed byGo runtimeOS kernel
Batas praktis100.000+~10.000

Untuk membuat goroutine, tambahkan keyword go sebelum pemanggilan fungsi:

main.go
 1package main
 2
 3import (
 4    "fmt"
 5    "sync"
 6)
 7
 8func sayHello(name string, wg *sync.WaitGroup) {
 9    defer wg.Done()
10    fmt.Printf("Halo, %s!\n", name)
11}
12
13func main() {
14    var wg sync.WaitGroup
15    names := []string{"Santekno", "Pembaca", "Gopher"}
16
17    for _, name := range names {
18        wg.Add(1)
19        go sayHello(name, &wg) // jalankan sebagai goroutine
20    }
21    wg.Wait() // tunggu semua goroutine selesai
22}
Caution
Jangan pakai time.Sleep untuk menunggu goroutine di production. Pakai sync.WaitGroup seperti contoh di atas, atau channel untuk sinkronisasi eksplisit.

Channel: Pipa Komunikasi antar Goroutine

Don’t communicate by sharing memory; share memory by communicating. — Rob Pike

Channel adalah mekanisme komunikasi goroutine di Go. Dibanding shared memory (mutex), channel membuat aliran data lebih eksplisit dan mudah di-reason.

Channel adalah pipa yang menghubungkan goroutine. Kirim data dengan operator <- dan terima dengan <-:

channel.go
1// Buat buffered channel berkapasitas 1
2ch := make(chan string, 1)
3
4go func() {
5    ch <- "halo dari goroutine" // kirim ke channel
6}()
7
8msg := <-ch // terima dari channel
9fmt.Println(msg) // Output: halo dari goroutine

Jenis Channel

Ada tiga varian channel yang perlu kamu tahu:

  1. Unbuffered — pengirim menunggu penerima siap. Cocok untuk sinkronisasi ketat.
  2. Buffered — pengirim tidak menunggu selama buffer belum penuh. Cocok untuk decoupling ringan.
  3. Directional — membatasi operasi (kirim atau terima saja) di signature fungsi.
JenisSintaksKapan dipakai
Unbufferedmake(chan T)Sinkronisasi ketat antara goroutine
Bufferedmake(chan T, N)Decoupling, N item bisa antre
Send-onlychan<- TFungsi hanya boleh kirim
Receive-only<-chan TFungsi hanya boleh terima
Tip
Gunakan buffered channel dengan kapasitas yang dipikirkan matang. Buffer terlalu kecil → goroutine sering block. Buffer terlalu besar → memory waste dan goroutine leak tidak terdeteksi.

Diagram: Arsitektur Goroutine

MERMAID
flowchart LR
    Main["main()"] -- "go func()" --> G1["Goroutine 1"]
    Main -- "go func()" --> G2["Goroutine 2"]
    Main -- "go func()" --> G3["Goroutine 3"]
    G1 -- "ch <- data" --> Ch[("Channel")]
    G2 -- "ch <- data" --> Ch
    G3 -- "ch <- data" --> Ch
    Ch -- "<-ch" --> Consumer["Consumer\ngoroutine"]

Pattern: Worker Pool

Worker pool adalah pattern untuk membatasi concurrency — misal, maksimal 5 request HTTP berjalan bersamaan:

worker_pool.go
 1func workerPool(numWorkers int, jobs <-chan int, results chan<- int) {
 2    var wg sync.WaitGroup
 3    for i := 0; i < numWorkers; i++ {
 4        wg.Add(1)
 5        go func() {
 6            defer wg.Done()
 7            for job := range jobs {
 8                results <- processJob(job)
 9            }
10        }()
11    }
12    go func() {
13        wg.Wait()
14        close(results) // tutup channel setelah semua worker selesai
15    }()
16}
Tip
Gunakan errgroup dari golang.org/x/sync untuk worker pool dengan error handling yang lebih ergonomis.

Perhatikan baris kritis di bawah — parameter hl="3,8-10" menyorot baris 3 dan baris 8–10:

worker_pool_highlight.go
 1func workerPool(numWorkers int, jobs <-chan int, results chan<- int) {
 2    var wg sync.WaitGroup
 3    sem := make(chan struct{}, numWorkers) // semaphore membatasi concurrency
 4    for job := range jobs {
 5        wg.Add(1)
 6        go func(j int) {
 7            defer wg.Done()
 8            sem <- struct{}{}        // acquire slot
 9            results <- processJob(j) // kerja utama
10            <-sem                    // release slot
11        }(job)
12    }
13    wg.Wait()
14    close(results)
15}

Select: Multiplex Channel

select seperti switch tapi untuk operasi channel — menunggu channel mana yang siap lebih dulu:

select.go
 1ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
 2defer cancel()
 3
 4select {
 5case msg := <-ch1:
 6    fmt.Println("dari ch1:", msg)
 7case msg := <-ch2:
 8    fmt.Println("dari ch2:", msg)
 9case <-ctx.Done():
10    fmt.Println("timeout atau dibatalkan:", ctx.Err())
11}

Pola select dengan default

Pakai default clause untuk non-blocking check:

go
1select {
2case msg := <-ch:
3    fmt.Println("ada data:", msg)
4default:
5    fmt.Println("tidak ada data, lanjut...")
6}
Aturan
Hindari select {} tanpa default atau case yang bisa selesai — itu menyebabkan goroutine block selamanya dan goroutine leak yang sulit debug.

Checklist Sebelum Deploy Goroutine ke Production

  • Goroutine memang perlu berjalan paralel (bukan sekadar bisa)
  • Ada mekanisme sinkronisasi: WaitGroup, channel, atau errgroup
  • Goroutine punya jalan keluar yang jelas — tidak akan berjalan selamanya
  • Context cancellation diteruskan ke semua goroutine child
  • Error dari goroutine dikembalikan ke caller
  • Race condition dicek dengan go test -race
  • Goroutine count dipantau di production (misal via pprof)
Danger
Goroutine leak adalah sumber memory leak paling sering dan paling sulit dideteksi di aplikasi Go. Setiap goroutine yang tidak punya titik selesai akan terus berjalan selamanya — bahkan setelah request selesai.

Ringkasan

Goroutine dan channel membuat concurrency di Go terasa natural. Tiga hal yang perlu diingat:

  1. Goroutine ringan — buat sebanyak yang diperlukan, runtime yang mengatur penjadwalannya
  2. Channel untuk komunikasi — hindari shared memory jika bisa diganti channel
  3. Context untuk shutdown — selalu pakai context.Context di goroutine production

Selanjutnya, di artikel berikutnya kita akan masuk ke error handling idiomatic di Go — cara Go menangani kesalahan tanpa exception.


Apakah ada pertanyaan? Tinggalkan komentar di bawah atau hubungi via halaman tentang saya .

Artikel Terkait

💬 Komentar