Go by Example မြန်မာဘာသာ: WaitGroups

Goroutine အများကြီး ပြီးဆုံးတာကို စောင့်ဆိုင်းဖို့ wait group ကို သုံးနိုင်ပါတယ်။

package main
import (
    "fmt"
    "sync"
    "time"
)

ဒါက goroutine တိုင်းမှာ run မယ့် function ပါ။

func worker(id int) {
    fmt.Printf("Worker %d starting\n", id)

expensive ဖြစ်တဲ့ အလုပ်တစ်ခုလိုမျိုးဖြစ်ဖို့ simulate လုပ်ပီး slepp လုပ်ခိုင်းထားပါတယ်။

    time.Sleep(time.Second)
    fmt.Printf("Worker %d done\n", id)
}
func main() {

ဒီ WaitGroup ကို ဒီမှာ စတင်လိုက်တဲ့ goroutine အားလုံး ပြီးဆုံးတာကို စောင့်ဆိုင်းဖို့ သုံးပါတယ်။ မှတ်ချက်: WaitGroup ကို function တွေဆီ တိုက်ရိုက်ပေးပို့မယ်ဆိုရင် pointer နဲ့ ပို့သင့်ပါတယ်။

    var wg sync.WaitGroup

Goroutine အများကြီးကို စတင်ပြီး WaitGroup ရဲ့ counter ကို တစ်ခုချင်းစီ တိုးလိုက်ပါမယ်။

    for i := 1; i <= 5; i++ {
        wg.Add(1)

Goroutine closure တိုင်းမှာ တူညီတဲ့ i တန်ဖိုးကို ပြန်သုံးတာကို ရှောင်ပါ။ ပိုမိုအသေးစိတ်သိချင်ရင် FAQ ကို ကြည့်ပါ။

        i := i

Worker ခေါ်တာကို closure တစ်ခုနဲ့ wrap ထားဖြင့် ဒီ closure က ဒီ worker ပြီးဆုံးကြောင်းကို WaitGroup ကို အသိပေးပါတယ်။ ဒီနည်းနဲ့ worker ကိုယ်တိုင်က သူ့ကို run တဲ့ concurrency primitive တွေအကြောင်း သိစရာမလိုတော့ပါဘူး။

        go func() {
            defer wg.Done()
            worker(i)
        }()
    }

WaitGroup counter က 0 ပြန်ဖြစ်တဲ့အထိ block လုပ်ထားပါတယ်။ Worker အားလုံးက သူတို့ပြီးဆုံးကြောင်း အသိပေးတဲ့အထိစောင့်မှာပါ။

    wg.Wait()

မှတ်ချက်: ဒီနည်းလမ်းက worker တွေကနေ error တွေကို ပြန်ပို့ဖို့ straightforward မဖြစ်ပါဘူး။ ပိုပြီးအဆင့်မြင့်တဲ့ use case တွေအတွက်ဆိုရင် errgroup package ကို consider လုပ်ပါ။

}
$ go run waitgroups.go
Worker 5 starting
Worker 3 starting
Worker 4 starting
Worker 1 starting
Worker 2 starting
Worker 4 done
Worker 1 done
Worker 2 done
Worker 5 done
Worker 3 done

Worker တွေ စတင်တဲ့အစီအစဉ်နဲ့ ပြီးဆုံးတဲ့အစီအစဉ်က ပရိုဂရမ်ကို run တိုင်း ကွာခြားနိုင်ပါတယ်။

နောက်ဥပမာ: Rate Limiting.