Apps Artificial Intelligence CSS DevOps Go JavaScript Laravel Linux MongoDB MySQL PHP Python Rust Vue

Mengelola Antrean Goroutine dengan Efisien di Go

2 min read .
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.

Lihat Juga

chevron-up