Pelajaran modul (4/5)
`sinkronisasi.Mutex` dan `sinkronisasi.WaitGroup`
Saluran adalah idiom utama Go, namun terkadang lebih tradisional
primitif diperlukan. Paket sync menyediakan mutex, tunggu
kelompok dan utilitas lain untuk mengoordinasikan keadaan bersama.
sync.Mutex: kunci eksklusif
import "sync"
type Counter struct {
mu sync.Mutex
count int
}
func (c *Counter) Inc() {
c.mu.Lock()
defer c.mu.Unlock()
c.count++
}
func (c *Counter) Get() int {
c.mu.Lock()
defer c.mu.Unlock()
return c.count
}Hanya satu goroutine dalam satu waktu yang masuk antara Lock() dan Unlock().
Pola wajib: defer mu.Unlock() tepat setelah Lock().
sync.RWMutex: banyak pembaca, satu penulis
Untuk kondisi baca-berat:
var mu sync.RWMutex
mu.RLock() // read lock: più goroutine simultanee OK
v := data
mu.RUnlock()
mu.Lock() // write lock: esclusivo
data = newValue
mu.Unlock()Berguna hanya jika pembacaan benar-benar mendominasi penulisan; jika tidak, biasa saja
sync.Mutex lebih sederhana dan seringkali lebih cepat berkat internal yang lebih rendah
perselisihan.
sync.WaitGroup: tunggu N goroutine
var wg sync.WaitGroup
for i := 0; i < 3; i++ {
wg.Add(1)
go func(id int) {
defer wg.Done()
work(id)
}(i)
}
wg.Wait() // blocca finché tutti i Done() sono arrivatiAlur kerja:
wg.Add(N)menambah penghitung sebesar N (sebelum meluncurkan goroutine).- Setiap goroutine memanggil
wg.Done()setelah selesai (idealnya melaluidefer). wg.Wait()blok hingga penghitung kembali ke 0.
sync.Once: inisialisasi malas yang aman untuk thread
var (
once sync.Once
config *Config
)
func GetConfig() *Config {
once.Do(func() {
config = loadConfig()
})
return config
}Callback di once.Do berjalan tepat sekali, bahkan dalam kondisi bersamaan
panggilan. Pola inisialisasi singleton/malas.
Mutex vs saluran: kapan menggunakan apa
Pedoman (juga dari FAQ resmi Go):
| Kasus | Alat pilihan |
|---|---|
| Melewati kepemilikan data | saluran |
| Mendistribusikan pekerjaan (antrian pekerjaan) | saluran |
| Mengkoordinasikan goroutine independen | saluran |
| Melindungi bidang struct | Muteks |
| Tembolok/penghitung | Mutex atau atomik |
| Referensi tunggal | sync.Once |
"Saluran untuk diatur, mutex untuk data bersama" adalah aturan praktis yang baik.
Detektor balapan
Jalankan pengujian dengan -race untuk menemukan data race:
go test -race ./...
go run -race main.goDetektor balapan menginstrumentasikan biner dan mencatat setiap hal yang tidak disinkronkan akses ke memori bersama. Ini adalah alat #1 untuk memvalidasi kode bersamaan sebelum produksi.
Cobalah
Lindungi penambahan hitungan dengan mu.Lock() + defer mu.Unlock().
Tunjukkan petunjuk
tunda mu.Unlock() tepat setelah Lock() menjamin pelepasan bahkan saat panik.
Solusi tersedia setelah 3 upaya
Luncurkan 3 goroutine dan tunggu semuanya menggunakan sync.WaitGroup (Tambahkan(3), Selesai() di setiap goroutine, Tunggu()).
Tunjukkan petunjuk
Tambahkan SEBELUM meluncurkan goroutine; Selesai DI DALAM goroutine dengan penundaan.
Solusi tersedia setelah 3 upaya
Pola apa yang direkomendasikan untuk menjamin mutex dilepaskan?
mu.Lock()
// ?Rekap
sync.Mutexmelindungi negara bersama; selaludefer mu.Unlock().- Gunakan penerima penunjuk untuk menghindari penyalinan mutex.
sync.RWMutexuntuk pola banyak pembaca/satu penulis (hanya jika membantu).sync.WaitGroup:Addsebelumgo,Donedengandefer,Waitmenunggu.sync.Once: inisialisasi lambat yang aman untuk thread.- "Saluran untuk diatur, mutex untuk data bersama".
go test -race: alat #1 untuk mengenali data race.