Mengelola Antrean Goroutine dengan Efisien di Go
Salah satu alasan Go populer adalah karena goroutine. Dengan keyword go
, saya bisa jalanin fungsi secara konkuren dengan overhead super ringan. Tapi ada satu masalah klasik:
Kalau goroutine diluncurkan tanpa kontrol, jumlahnya bisa meledak dan malah bikin server ngos-ngosan.
Solusinya: saya butuh cara mengantrekan goroutine biar eksekusinya terkontrol, rapi, dan efisien.
Apa Itu Goroutine (singkat aja)
Goroutine = thread ringan versi Go. Contoh paling basic:
go func() {
fmt.Println("Running in a goroutine")
}()
Udah, sesederhana itu. Tapi, bayangin kalau ada ribuan task yang semua dijalanin pakai go
langsung—bisa bahaya kalau nggak dibatasi.
Kenapa Perlu Antrean?
Beberapa alasan:
- Biar jumlah goroutine aktif nggak kebanyakan dan ngabisin resource.
- Biar task diproses dalam urutan tertentu.
- Lebih gampang monitor dan kontrol beban kerja.
1. Antrean Dasar dengan Channel
Channel di Go bisa jadi “antrean tugas”. Worker tinggal narik job dari situ.
type Task struct {
ID int
}
func worker(id int, tasks <-chan Task) {
for task := range tasks {
fmt.Printf("Worker %d ngerjain task %d\n", id, task.ID)
time.Sleep(time.Second) // simulasi kerja
}
}
func main() {
numWorkers := 3
tasks := make(chan Task, 10)
for i := 1; i <= numWorkers; i++ {
go worker(i, tasks)
}
for i := 1; i <= 10; i++ {
tasks <- Task{ID: i}
}
close(tasks)
time.Sleep(5 * time.Second) // kasih waktu worker selesai
}
Di sini ada 3 worker yang “berebut” tugas dari antrean.
2. Worker Pool dengan WaitGroup
Kalau mau lebih rapi, kita bisa pakai worker pool.
const numWorkers = 3
type Task struct {
ID int
}
func worker(id int, tasks <-chan Task, wg *sync.WaitGroup) {
defer wg.Done()
for task := range tasks {
fmt.Printf("Worker %d ngerjain task %d\n", id, task.ID)
time.Sleep(time.Second)
}
}
func main() {
tasks := make(chan Task, 10)
var wg sync.WaitGroup
for i := 1; i <= numWorkers; i++ {
wg.Add(1)
go worker(i, tasks, &wg)
}
for i := 1; i <= 10; i++ {
tasks <- Task{ID: i}
}
close(tasks)
wg.Wait()
}
Di sini kita pakai sync.WaitGroup
biar program bisa nunggu semua worker selesai sebelum keluar.
3. Teknik Lanjutan
- Antrean Prioritas → kalau ada task yang lebih penting, bisa bikin antrean khusus dengan struktur data
heap
. - Rate Limiting → batasi jumlah task per detik supaya sistem nggak kepayahan.
Kesimpulan
Goroutine itu ringan, tapi kalau dilepas liar bisa jadi bumerang. Dengan pola channel + worker pool, kita bisa:
- Batasi jumlah goroutine aktif.
- Proses job secara lebih teratur.
- Buat aplikasi yang lebih stabil dan efisien.
Buat use case simpel, cukup channel. Kalau workload makin kompleks, worker pool dengan opsi tambahan kayak prioritas dan rate limiting bisa jadi solusi.