Go Sync
Definisi
Package sync menyediakan primitive untuk mengkoordinasikan goroutine: sync.WaitGroup untuk menunggu banyak goroutine selesai, sync.Mutex/sync.RWMutex untuk mutual exclusion, sync.Once untuk inisialisasi sekali jalan, dan sync.Pool untuk reuse objek. Untuk counter sederhana, sync/atomic lebih ringan.
Kapan dipakai
- WaitGroup: spawn N worker lalu tunggu semua selesai sebelum lanjut.
- Mutex: akses bersama ke map/struct yang bisa diubah dari banyak goroutine.
- RWMutex: banyak baca, jarang tulis (cache, config).
- Once: lazy init yang harus sekali saja (singleton, setup DB).
- atomic: increment/decrement atau flag tanpa mutex penuh.
Cara kerja
WaitGroup
var wg sync.WaitGroup
for _, item := range items {
wg.Add(1)
go func(it Item) {
defer wg.Done()
process(it)
}(item)
}
wg.Wait() // blok sampai semua Done()Add harus dipanggil di goroutine pembawa, bukan di dalam goroutine yang di-spawning, supaya Wait tidak kebagian race.
Mutex
type Counter struct {
mu sync.Mutex
n int
}
func (c *Counter) Inc() {
c.mu.Lock()
defer c.mu.Unlock()
c.n++
}Gunakan defer Unlock agar tidak lupa buka kunci saat panic/return.
Once
var once sync.Once
var db *sql.DB
func getDB() *sql.DB {
once.Do(func() {
db = connect()
})
return db
}atomic
var hits atomic.Int64
hits.Add(1)
_ = hits.Load()Struktur alur
Loading diagram...
Contoh RWMutex
type Cache struct {
mu sync.RWMutex
m map[string]string
}
func (c *Cache) Get(k string) string {
c.mu.RLock()
defer c.mu.RUnlock()
return c.m[k]
}
func (c *Cache) Set(k, v string) {
c.mu.Lock()
defer c.mu.Unlock()
c.m[k] = v
}Catatan implementasi
- Jangan copy struct yang berisi
sync.Mutexsetelah dipakai; pass lewat pointer. defer Unlocklebih aman daripada panggil manual di tiap cabang.sync.Poolbagus untuk objek besar yang sering dialokasi/GC, bukan untuk state yang harus persisten.
Kesalahan umum
- Add di dalam goroutine: race dengan
Wait, hasil non-deterministik. - Lupa Done:
Waitblock selamanya (deadlock). - Copy mutex: menyalin struct ber-mutex, kunci jadi tidak berbagi.
- Hold lock terlalu lama: melakukan I/O di dalam critical section, goroutine lain kelaparan.
- Mutex vs atomic salah pilih: pakai mutex untuk sekadar counter padahal
atomiccukup.