Go'da, eşzamanlı goroutinelerin senkronizasyonu için sync paketinden yapılar kullanılır; en yaygın olanları sync.Mutex, sync.RWMutex ve sync.WaitGroup'dır.
sync.Mutex paylaşılan verilere erişim sırasında karşılıklı dışlama mekanizmaları sunar. Metotları — Lock() (kilitler) ve Unlock() (kapatır).
sync.RWMutex klasik mutex'in imkanlarını genişleterek: eşzamanlı okumaya ancak özel değişikliklere izin verir.
sync.WaitGroup bir grup goroutine'in tamamlanmasını beklemek için tasarlanmıştır. Add(int), Done() ve Wait() ile eşzamanlı çalışmanın yaşam döngüsünü yönetebilirsiniz.
Örneğin:
var mu sync.RWMutex data := 0 // Okuma mu.RLock() fmt.Println(data) mu.RUnlock() // Yazma mu.Lock() data = 42 mu.Unlock()
İncelikler:
Unlock'ı bir defer bloğunda kullanın, böylece panic durumunda bile mutex'i açmayı unutmazsınız.WaitGroup.Done() çağrılarının sayısının Add() ile eşleştiğinden emin olun.Aynı goroutine içinde sync.Mutex (veya RWMutex) iki kez üst üste alabilir misiniz? Ne olur?
Cevap: Hayır, eğer aynı Mutex üzerinde Lock() çağrısı yaparsanız iki kez ardışık olarak arada Unlock() olmadan, goroutine sonsuza dek kilitlenecektir (deadlock). Go'da mutex'ler rekürsif değildir.
Örnek:
var mu sync.Mutex mu.Lock() // ... mu.Lock() // DEADLOCK: sonsuza kadar kilitlenir, çünkü aynı iş parçacığı zaten kilidi tutuyor
Hikaye
Yüksek yükteki bir REST API projesinde, geliştirici tüm isteği tek bir mutex ile sarmaladı. Bu, yalnızca bir isteğin aynı anda işlenebilmesini sağladı ve bu da performansta keskin bir düşüşe yol açtı — binlerce müşterinin hizmet alması planlanmıştı. Sebep - Mutex ile RWMutex arasındaki farkın bilinmemesi ve eşzamanlı okumaların göz ardı edilmesidir.
Hikaye
Ekip üyelerinden biri, içinde Mutex bulunan bir yapıyı kopyalarken, yanlışlıkla kopyayı başka bir işlevde iletti. Bu, "sync: copy of sync.Mutex" hatası ve yüksek yük altında prod'da çöküşe neden oldu.
Hikaye
WaitGroup kullanırken, birkaç goroutine'de Done() çağrısını unuttular, bu da Wait()'in sonsuza dek beklemesine neden oldu ve ana iş parçacığını engelledi. Sonuç olarak, hizmet manuel yeniden başlatmaya kadar erişim kaybı yaşadı.