A.59. WaitGroup

Sebelumnya kita telah belajar banyak mengenai channel, yang fungsi utama-nya adalah untuk sharing data antar goroutine. Selain untuk komunikasi data, channel secara tidak langsung bisa dimanfaatkan untuk kontrol goroutine.

Go menyediakan package sync, berisi cukup banyak API untuk handle masalah multiprocessing (goroutine), salah satunya di antaranya adalah yang kita bahas pada chapter ini, yaitu sync.WaitGroup.

Kegunaan sync.WaitGroup adalah untuk sinkronisasi goroutine. Berbeda dengan channel, sync.WaitGroup memang dirancang khusus untuk maintain goroutine, penggunaannya lebih mudah dan lebih efektif dibanding channel.

Sebenarnya kurang pas jika membandingkan sync.WaitGroup dan channel, karena fungsi utama dari keduanya adalah berbeda. Channel untuk keperluan sharing data antar goroutine, sedangkan sync.WaitGroup untuk sinkronisasi goroutine.

A.59.1. Penerapan sync.WaitGroup

sync.WaitGroup digunakan untuk menunggu goroutine. Cara penggunaannya sangat mudah, tinggal masukan jumlah goroutine yang dieksekusi, sebagai parameter method Add() object cetakan sync.WaitGroup. Dan pada akhir tiap-tiap goroutine, panggil method Done(). Juga, pada baris kode setelah eksekusi goroutine, panggil method Wait().

Agar lebih jelas, silakan coba kode berikut.

package main

import "sync"
import "runtime"
import "fmt"

func doPrint(wg *sync.WaitGroup, message string) {
    defer wg.Done()
    fmt.Println(message)
}

func main() {
    runtime.GOMAXPROCS(2)

    var wg sync.WaitGroup

    for i := 0; i < 5; i++ {
        var data = fmt.Sprintf("data %d", i)

        wg.Add(1)
        go doPrint(&wg, data)
    }

    wg.Wait()
}

Kode di atas merupakan contoh penerapan sync.WaitGroup untuk pengelolahan goroutine. Fungsi doPrint() akan dijalankan sebagai goroutine, dengan tugas menampilkan isi variabel message.

Variabel wg disiapkan bertipe sync.WaitGroup, dibuat untuk sinkronisasi goroutines yang dijalankan.

Di tiap perulangan statement wg.Add(1) dipanggil. Kode tersebut akan memberikan informasi kepada wg bahwa jumlah goroutine yang sedang di proses ditambah 1 (karena dipanggil 5 kali, maka wg akan sadar bahwa terdapat 5 buah goroutine sedang berjalan).

Di baris selanjutnya, fungsi doPrint() dieksekusi sebagai goroutine. Di dalam fungsi tersebut, sebuah method bernama Done() dipanggil. Method ini digunakan untuk memberikan informasi kepada wg bahwa goroutine di mana method itu dipanggil sudah selesai. Sejumlah 5 buah goroutine dijalankan, maka method tersebut harus dipanggil 5 kali.

Statement wg.Wait() bersifat blocking, proses eksekusi program tidak akan diteruskan ke baris selanjutnya, sebelum sejumlah 5 goroutine selesai. Jika Add(1) dipanggil 5 kali, maka Done() juga harus dipanggil 5 kali.

Output program di atas.

Dasar Pemrograman Golang - Contoh penerapan `sync.WaitGroup`

sync.WaitGroup merupakan salah satu tipe yang thread safe. Kita tidak perlu khawatir terhadap potensi race condition karena variabel bertipe ini aman untuk digunakan di banyak goroutine secara paralel.

A.59.2. Perbedaan WaitGroup Dengan Channel

Bukan sebuah perbandingan yang valid, tapi jika dibandingkan maka perbedaan antara channel dan sync.WaitGroup kurang lebih sebagai berikut:

  • Channel tergantung kepada goroutine tertentu dalam penggunaannya, tidak seperti sync.WaitGroup yang dia tidak perlu tahu goroutine mana saja yang dijalankan, cukup tahu jumlah goroutine yang harus selesai
  • Penerapan sync.WaitGroup lebih mudah dibanding channel
  • Kegunaan utama channel adalah untuk komunikasi data antar goroutine. Sifatnya yang blocking bisa kita manfaatkan untuk manage goroutine; sedangkan WaitGroup khusus digunakan untuk sinkronisasi goroutine
  • Performa sync.WaitGroup lebih baik dibanding channel, sumber: https://groups.google.com/forum/#!topic/golang-nuts/whpCEk9yLhc

Kombinasi yang tepat antara sync.WaitGroup dan channel sangat penting, keduanya diperlukan dalam concurrent process agar bisa maksimal.