ပြီးခဲ့တဲ့ဥပမာမှာ atomic operation တွေသုံးပြီး ရိုးရှင်းတဲ့ counter state ကို ဘယ်လိုစီမံခန့်ခွဲသလဲဆိုတာ တွေ့ခဲ့ပါတယ်။ ပိုရှုပ်ထွေးတဲ့ state တွေအတွက်တော့ goroutine အများကြီးကြားထဲမှာ ဒေတာကို လုံခြုံစွာ access လုပ်ဖို့ mutex ကို သုံးနိုင်ပါတယ်။ |
|
package main |
|
import ( "fmt" "sync" ) |
|
Container က counter တွေရဲ့ map ကို သိမ်းထားပါတယ်။ ဒီ map ကို
goroutine အများကြီးကနေ တပြိုင်နက်တည်း update လုပ်ချင်တဲ့အတွက်
access ကို synchronize လုပ်ဖို့ |
type Container struct { mu sync.Mutex counters map[string]int } |
|
func (c *Container) inc(name string) { |
c.mu.Lock() defer c.mu.Unlock() c.counters[name]++ } |
|
Mutex ရဲ့ zero value က အသုံးပြုလို့ရပါတယ်၊ ဒါကြောင့် ဒီမှာ သီးခြား initialization လုပ်စရာမလိုပါဘူး။ |
func main() { c := Container{ |
counters: map[string]int{"a": 0, "b": 0}, } |
|
var wg sync.WaitGroup |
|
ဒီ function က နာမည်ပေးထားတဲ့ counter ကို loop ထဲမှာ တိုးပေးပါတယ်။ |
doIncrement := func(name string, n int) { for i := 0; i < n; i++ { c.inc(name) } wg.Done() } |
Goroutine အများကြီးကို တပြိုင်နက်တည်း run တာပါ။
သတိပြုရမှာက သူတို့အားလုံးက တူညီတဲ့ |
wg.Add(3) go doIncrement("a", 10000) go doIncrement("a", 10000) go doIncrement("b", 10000) |
Goroutine တွေ ပြီးဆုံးတဲ့အထိ စောင့်ပါ |
wg.Wait() fmt.Println(c.counters) } |
ပရိုဂရမ်ကို run လိုက်တဲ့အခါ counter တွေက ကျွန်တော်တို့ မျှော်လင့်ထားသလိုပဲ update ဖြစ်သွားတာကို တွေ့ရပါတယ်။ |
$ go run mutexes.go map[a:20000 b:10000] |
နောက်တစ်ဆင့်မှာ ဒီလို state စီမံခန့်ခွဲမှုကိုပဲ goroutine တွေနဲ့ channel တွေကိုပဲ သုံးပြီး အကောင်အထည်ဖော်တာကို ကြည့်ကြပါမယ်။ |
နောက်ဥပမာ: Stateful Goroutines.