ProgramlamaBackend geliştirici

Go'da senkronizasyon çeşitleri nelerdir? sync.Mutex, sync.RWMutex ve sync.WaitGroup'ı nasıl kullanırız ve her bir durumda hangi incelikler vardır?

Hintsage yapay zeka asistanı ile mülakatları geçin

Cevap

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:

  • Her zaman 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.
  • WaitGroup, Mutex ve RWMutex'leri kopyalamayın!

Kandırmaca Soru

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

Gerçek Hata Örnekleri


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ı.