مرکزی مواد پر جائیں
ماڈیول 7 · سبق 4 از 5کورس میں 34/50~14 min
ماڈیول اسباق (4/5)

`sync.Mutex` اور `sync.WaitGroup`

چینلز گو کا بنیادی محاورہ ہے، لیکن بعض اوقات زیادہ روایتی ہوتا ہے۔ primitives کی ضرورت ہے. sync پیکیج mutexes فراہم کرتا ہے، انتظار کریں۔ مشترکہ ریاست کو مربوط کرنے کے لیے گروپس اور دیگر افادیت۔

sync.Mutex: خصوصی تالا

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() اور Unlock() کے درمیان داخل ہوتا ہے۔ لازمی پیٹرن: defer mu.Unlock() کے ٹھیک بعد Lock()۔

sync.RWMutex: بہت سے قارئین، ایک مصنف

پڑھنے والی بھاری حالت کے لیے:

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

مفید صرف اس صورت میں جب پڑھنا واقعی لکھنے پر غالب ہے۔ دوسری صورت میں ایک باقاعدہ کم اندرونی کی بدولت sync.Mutex آسان اور اکثر تیز ہے۔ تنازعہ

Sync.WaitGroup: N goroutines کا انتظار کریں۔

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

ورک فلو:

  1. wg.Add(N) کاؤنٹر کو N سے بڑھاتا ہے (گوروٹینز شروع کرنے سے پہلے)۔
  2. ہر گوروٹین ختم ہونے پر wg.Done() کو کال کرتا ہے (مثالی طور پر defer کے ذریعے)۔
  3. wg.Wait() بلاک کرتا ہے جب تک کہ کاؤنٹر 0 پر واپس نہ جائے۔

sync.Once: تھریڈ سے محفوظ سست ابتدا

Go
var (
    once   sync.Once
    config *Config
)

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

once.Do میں کال بیک بالکل ایک بار چلتا ہے، یہاں تک کہ ہم آہنگی کے تحت بھی کالز سنگلٹن / سست ابتداء کا نمونہ۔

Mutex بمقابلہ چینل: کب استعمال کرنا ہے۔

رہنما خطوط (آفیشل Go FAQ سے بھی):

کیسترجیحی ٹول
ڈیٹا کی ملکیت پاس کرناچینل
کام کی تقسیم (کام کی قطار)چینل
آزاد گوروٹینز کو مربوط کرناچینل
ڈھانچے کے میدان کی حفاظت کرناMutex
کیش / کاؤنٹرMutex یا جوہری
سنگلٹن حوالہsync.Once

"آرکیسٹریٹ کرنے کے لیے چینلز، مشترکہ ڈیٹا کے لیے mutexes" انگوٹھے کا ایک اچھا اصول ہے۔

ریس کا پتہ لگانے والا

ڈیٹا ریس کو اسپاٹ کرنے کے لیے -race کے ساتھ ٹیسٹ چلائیں:

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

ریس کا پتہ لگانے والا بائنری کو آلات بناتا ہے اور ہر غیر مطابقت پذیر کو لاگ کرتا ہے۔ مشترکہ میموری تک رسائی۔ سمورتی کوڈ کی توثیق کرنے کے لیے یہ ٹول نمبر 1 ہے۔ پیداوار سے پہلے.

اسے آزمائیں

ورزش#go.m7.l4.e1
کوششیں: 0لوڈ ہو رہا ہے…

mu.Lock() + defer mu.Unlock() کے ساتھ گنتی میں اضافے کی حفاظت کریں۔

ایڈیٹر لوڈ ہو رہا ہے…
اشارہ دکھائیں۔

گھبراہٹ میں بھی Lock() ریلیز کی گارنٹی دینے کے بعد mu.Unlock() کو موخر کریں۔

3 کوششوں کے بعد حل دستیاب ہے۔

ورزش#go.m7.l4.e2
کوششیں: 0لوڈ ہو رہا ہے…

3 گورٹائنز لانچ کریں اور ان سب کا sync.WaitGroup (Add(3)، Done() ہر گوروٹائن میں، Wait()) کا استعمال کرتے ہوئے انتظار کریں۔

ایڈیٹر لوڈ ہو رہا ہے…
اشارہ دکھائیں۔

گوروٹین شروع کرنے سے پہلے شامل کریں۔ ڈیفر کے ساتھ گوروٹین کے اندر ہو گیا۔

3 کوششوں کے بعد حل دستیاب ہے۔

Quiz#go.m7.l4.e3
تیار

mutex جاری ہونے کی ضمانت کے لیے تجویز کردہ پیٹرن کیا ہے؟

Go
mu.Lock()
// ?
جواب کے اختیارات

Recap

  • sync.Mutex مشترکہ ریاست کی حفاظت کرتا ہے؛ ہمیشہ defer mu.Unlock()
  • mutex کاپی کرنے سے بچنے کے لیے پوائنٹر ریسیور استعمال کریں۔
  • sync.RWMutex بہت سے قارئین/ایک مصنف کے نمونوں کے لیے (صرف اس صورت میں جب اس سے مدد ملتی ہے)۔
  • sync.WaitGroup: Add سے پہلے go، Done کے ساتھ defer، Wait انتظار کرنے کے لئے۔
  • sync.Once: تھریڈ سے محفوظ سست ابتدا۔
  • "آرکیسٹریٹ کے لیے چینلز، مشترکہ ڈیٹا کے لیے mutexes"۔
  • go test -race: ٹول نمبر 1 ڈیٹا ریس کو تلاش کرنے کے لیے۔