Sobes.tech
Middle

Go'da mutexlerle çalışırken neyi hatırlamak gerekir?

sobes.tech yapay zeka

AI'dan gelen yanıt

Go dilinde (sync.Mutex) mutexlerle çalışırken aşağıdakileri hatırlamak önemlidir:

  • Kilit ve serbest bırakma: Mutex mutlaka (Lock()) paylaşılan verilere erişmeden önce kilitlenmeli ve iş tamamlandıktan sonra (Unlock()) serbest bırakılmalıdır. defer mu.Unlock() kullanımı, mu.Lock() hemen ardından, unutmayı önlemek için iyi bir uygulamadır.
  • Özel erişim: Mutex, aynı anda yalnızca bir goroutine'un kaynağa erişmesine izin verir.
  • "Kilitleme/açma" durumu: Bir mutex zaten kilitliyken tekrar Lock() çağrısı, çağıran goroutine'in başka bir goroutine serbest bırakana kadar bloke olmasına neden olur. Kilitli olmayan bir mutex üzerinde Unlock() çağrısı ise çalışma zamanında panik oluşturur.
  • Mutexleri kopyalamayın: sync.Mutex yapısı, ilk kullanım sonrası kopyalanmak üzere tasarlanmamıştır. Bir mutex'i değeriyle geçirmek veya mutex içeren yapıyı kopyalamak, yanlış senkronizasyon ve paniklere yol açabilir.
  • Deadlock (ölüm kilidi): İki veya daha fazla goroutine'un birbirlerinin serbest bırakmasını beklediği durumdur. Tipik senaryo: A goroutine'u R1'i kilitler ve R2'yi bekler, B goroutine'u R2'yi kilitler ve R1'i bekler.
  • Livelock (canlı kilit): Goroutine'ların sürekli durum değiştirerek birbirlerinin hareketlerine yanıt verdiği, ancak işe yaramaz işler yaptığı ve ilerlemediği durumdur. Deadlock'tan daha az rastlanır.
  • Açlık (starvation): Bir veya birkaç goroutine'un, diğerleri sürekli olarak kilitlediği için paylaşılan kaynağa erişemediği durumdur. Go mutex'lerinde açlık garantilenmez.
  • sync.RWMutex kullanımı: Çoğu işlem okuma ise ve yazma nadiren yapılacaksa, sync.RWMutex daha verimli olabilir. Aynı anda birden fazla okuma yapılmasına izin verir, ancak yazma sırasında tüm okuma ve yazma işlemlerini engeller.
  • Kısa kilitler: Kilitleri mümkün olan en kısa sürede tutmaya çalışın. Mutex uzun süre kilitli kalırsa, diğer goroutine'lar bekler ve paralellik azalır.
  • Yarış durumu testi: -race bayrağı kullanmak, derleme ve test çalıştırırken (go test -race) yarış durumlarını tespit etmeye yardımcı olur.

defer kullanımı örneği:

import (
	"sync"
)

type SafeCounter struct {
	mu sync.Mutex
	v  map[string]int
}

// Inc, anahtar için sayacı güvenli bir şekilde artırır.
func (c *SafeCounter) Inc(key string) {
	c.mu.Lock()
	// Fonktan çıkarken serbest bırakmayı erteleyin.
	defer c.mu.Unlock()
	c.v[key]++
}

// Value, anahtar için mevcut sayacı döndürür.
func (c *SafeCounter) Value(key string) int {
	c.mu.Lock()
	// Değer alınana kadar serbest bırakılır.
	defer c.mu.Unlock()
	return c.v[key]
}