Ana içeriğe geç
Modül 7 · Ders 4 ders 5Kurstaki 34/50~14 min
Modül dersleri (4/5)

'sync.Mutex' ve 'sync.WaitGroup'

Kanallar Go'nun birincil deyimidir ancak bazen daha gelenekseldir ilkellere ihtiyaç var. sync paketi muteksleri sağlar, bekleyin Paylaşılan durumu koordine etmek için gruplar ve diğer yardımcı programlar.

senkronizasyon.Mutex: özel kilit

Go
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
}

Lock() ve Unlock() arasına aynı anda yalnızca bir goroutin girer. Zorunlu kalıp: defer mu.Unlock(), Lock()'den hemen sonra.

sink.RWMutex: birçok okuyucu, tek yazar

Okuma ağırlıklı durum için:

Go
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()

Yalnızca okumaların gerçekten yazmalara üstün gelmesi durumunda kullanışlıdır; aksi takdirde düzenli sync.Mutex daha düşük dahili hız sayesinde daha basit ve çoğu zaman daha hızlıdır çekişme.

senkronizasyon.WaitGroup: N goroutine'i bekleyin

Go
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 arrivati

İş akışı:

  1. wg.Add(N) sayacı N kadar artırır (goroutinleri başlatmadan önce).
  2. Her goroutine bittiğinde wg.Done() çağırır (ideal olarak defer aracılığıyla).
  3. wg.Wait() sayaç 0'a dönene kadar bloklar.

Sync.Once: iş parçacığı güvenli tembel başlatma

Go
var (
    once   sync.Once
    config *Config
)

func GetConfig() *Config {
    once.Do(func() {
        config = loadConfig()
    })
    return config
}

once.Do içindeki geri arama tam olarak bir kez, eşzamanlı olarak bile çalışır Aramalar. Singleton / tembel başlatma modeli.

Mutex vs kanal: ne zaman ne kullanılmalı

Yönergeler (aynı zamanda resmi Go SSS'sinden):

DurumTercih edilen araç
Verilerin sahipliğini aktarmakanal
İş dağıtımı (iş kuyruğu)kanal
Bağımsız goroutinlerin koordinasyonukanal
Yapı alanını korumaMuteks
Önbellek / sayaçMutex veya atomik
Singleton referansısync.Once

"Düzenlenecek kanallar, paylaşılan veriler için muteksler" iyi bir genel kuraldır.

Yarış dedektörü

Veri yarışlarını tespit etmek için -race ile testler yapın:

Bash
go test -race ./...
go run -race main.go

Yarış detektörü ikili dosyayı yönetir ve senkronize olmayan her şeyi günlüğe kaydeder Paylaşılan hafızaya erişim. Eşzamanlı kodu doğrulamak için 1 numaralı araçtır Üretimden önce.

Deneyin

Egzersiz#go.m7.l4.e1
Denemeler: 0Yükleniyor…

Sayım artışını mu.Lock() + defer mu.Unlock() ile koruyun.

Düzenleyici yükleniyor…
İpucu göster

defer mu.Unlock(), Lock()'tan hemen sonra panik halinde bile serbest bırakılmasını garanti eder.

3 denemeden sonra çözüm mevcut

Egzersiz#go.m7.l4.e2
Denemeler: 0Yükleniyor…

3 goroutine başlatın ve sink.WaitGroup (her goroutine'de Add(3), Done(), Wait()) kullanarak hepsini bekleyin.

Düzenleyici yükleniyor…
İpucu göster

Goroutini başlatmadan ÖNCE ekleyin; Erteleme ile Goroutinin İÇİNDE yapılır.

3 denemeden sonra çözüm mevcut

Quiz#go.m7.l4.e3
Hazır

Mutex'in serbest bırakılmasını garanti etmek için önerilen model nedir?

Go
mu.Lock()
// ?
Cevap seçenekleri

Özet

  • sync.Mutex paylaşılan durumu korur; her zaman defer mu.Unlock().
  • Muteksin kopyalanmasını önlemek için bir işaretçi alıcısı kullanın.
  • Çok okuyuculu/tek yazarlı kalıplar için sync.RWMutex (yalnızca yardımcı olması durumunda).
  • sync.WaitGroup: Add önce go, Done ile defer, Wait beklemek için.
  • sync.Once: iş parçacığı açısından güvenli tembel başlatma.
  • "Düzenlenecek kanallar, paylaşılan veriler için muteksler".
  • go test -race: veri yarışlarını tespit etmek için 1 numaralı araç.