ماڈیول اسباق (4/5)
`sync.Mutex` اور `sync.WaitGroup`
چینلز گو کا بنیادی محاورہ ہے، لیکن بعض اوقات زیادہ روایتی ہوتا ہے۔
primitives کی ضرورت ہے. sync پیکیج mutexes فراہم کرتا ہے، انتظار کریں۔
مشترکہ ریاست کو مربوط کرنے کے لیے گروپس اور دیگر افادیت۔
sync.Mutex: خصوصی تالا
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: بہت سے قارئین، ایک مصنف
پڑھنے والی بھاری حالت کے لیے:
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 کا انتظار کریں۔
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ورک فلو:
wg.Add(N)کاؤنٹر کو N سے بڑھاتا ہے (گوروٹینز شروع کرنے سے پہلے)۔- ہر گوروٹین ختم ہونے پر
wg.Done()کو کال کرتا ہے (مثالی طور پرdeferکے ذریعے)۔ wg.Wait()بلاک کرتا ہے جب تک کہ کاؤنٹر 0 پر واپس نہ جائے۔
sync.Once: تھریڈ سے محفوظ سست ابتدا
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 کے ساتھ ٹیسٹ چلائیں:
go test -race ./...
go run -race main.goریس کا پتہ لگانے والا بائنری کو آلات بناتا ہے اور ہر غیر مطابقت پذیر کو لاگ کرتا ہے۔ مشترکہ میموری تک رسائی۔ سمورتی کوڈ کی توثیق کرنے کے لیے یہ ٹول نمبر 1 ہے۔ پیداوار سے پہلے.
اسے آزمائیں
mu.Lock() + defer mu.Unlock() کے ساتھ گنتی میں اضافے کی حفاظت کریں۔
اشارہ دکھائیں۔
گھبراہٹ میں بھی Lock() ریلیز کی گارنٹی دینے کے بعد mu.Unlock() کو موخر کریں۔
3 کوششوں کے بعد حل دستیاب ہے۔
3 گورٹائنز لانچ کریں اور ان سب کا sync.WaitGroup (Add(3)، Done() ہر گوروٹائن میں، Wait()) کا استعمال کرتے ہوئے انتظار کریں۔
اشارہ دکھائیں۔
گوروٹین شروع کرنے سے پہلے شامل کریں۔ ڈیفر کے ساتھ گوروٹین کے اندر ہو گیا۔
3 کوششوں کے بعد حل دستیاب ہے۔
mutex جاری ہونے کی ضمانت کے لیے تجویز کردہ پیٹرن کیا ہے؟
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 ڈیٹا ریس کو تلاش کرنے کے لیے۔