WaitGroup — Goroutine'larni boshqarish
Bundan avvalgi mavzuda biz goroutine tushunchasi bilan tanishgan edik. Ushbu mavzuga o'tishdan oldin o'sha bilimlarni qisqacha yodga olib o'tish foydali bo'ladi.
Info
Go dasturlash tilida dastur salomilishi main()
funksiyasidan boshlanadi. Agar main()
funksiyasi o'z ishini yakunlasa,
butun dastur ham to'xtaydi. Bu holatda, Go tilida asosiy goroutine
deb aynan main()
funksiyasi qaraladi.
Yangi yaratilgan goroutine
lar esa ana shu asosiy goroutine
ustida ishlaydi.
Goroutine'lar bilan ishlaganda, ularning salomilishi tugashini kutish muhim bo'ladi. Avvalgi misolda biz bu muammoni
vaqtinchalik time.Sleep(time.Second)
funksiyasi orqali hal qilgan edik. Biroq bu usul samarali emas, chunki u aniq va
ishonchli boshqaruvni ta'minlamaydi.
Go ishlab chiquvchilari ushbu muammoni hal qilish uchun maxsus mexanizm sync.WaitGroup
paketini qo'shishgan.
WaitGroup
yordamida bir nechta goroutine
larni sinxronlashtirish va ularning boshqarish mumkin.
sync.WaitGroup'ning asosiy metodlari
Add(n int)
- ishga tushirilayotgan goroutine'lar sonini belgilaydi.Done()
- bitta goroutine ishini tugatganini bildiradi.Wait()
- barcha qo'shilgan goroutine'larDone()
bo'lishini kutadi.
Misol
package main
import (
"fmt"
"sync"
)
func salom(id int, wg *sync.WaitGroup) {
defer wg.Done() // Tugaganini bildiramiz
fmt.Println("Salom!", id)
}
func main() {
var wg sync.WaitGroup
for i := 1; i <= 5; i++ {
wg.Add(1) // Har bir goroutine uchun 1 qo'shamiz
go salom(i, &wg)
}
wg.Wait() // Barchasini tugashini kutamiz
fmt.Println("Barcha goroutine yakunlandi.")
}
Natija:
Kodni ishlatib ko'ring va taxlil qiling, sonlarni o'zgartirib yana ham chuqurroq kiring.
Yuqoridagi kodni ishlatib ko'rib wg.Add(1)
qiymatini wg.Add(n)
(n - ixtiyoriy son) ga o'zgartirsak nima bo'ladi
degan savol paydo bo'lgan bo'lishi mumkin, bu savolga quyida javob berib ketamiz:
Agar siz wg.Add(2)
deb yozsangiz, bu WaitGroup
ga 2 ta goroutine
tugashini kutish kerakligini bildiradi.
Shunday bo'lsa, siz ikki marta wg.Done()
metodini chaqirishingiz shart bo'ladi. Agar faqat bitta wg.Done()
chaqirilsa Wait()
abadiy kutishda qoladi (deadlock yuz berishi mumkin). Xulosa qilib aytganda wg.Add(n)
ni qiymati n
nechi bo'lsa shuncha marta Done()
chaqirilishi shart.
Misol:
package main
import (
"fmt"
"sync"
)
func salom(id int, wg *sync.WaitGroup) {
defer wg.Done()
fmt.Println("Salom", id)
}
func main() {
var wg sync.WaitGroup
wg.Add(2) // 2 ta goroutine kutamiz
go salom(1, &wg)
go salom(2, &wg) // 2 ta goroutine chaqirildi
wg.Wait()
fmt.Println("Barchasi tugadi")
}
Natija:
deadlock holatiga misol:
package main
import (
"fmt"
"sync"
)
func salom(id int, wg *sync.WaitGroup) {
defer wg.Done()
fmt.Println("Salom", id)
}
func main() {
var wg sync.WaitGroup
wg.Add(4) // 4 ta goroutine kutamiz
go salom(1, &wg)
go salom(2, &wg) // 2 ta goroutine chaqirildi
wg.Wait()
fmt.Println("Barchasi tugadi")
}
Natija:
WaitGroupning nozik jihatlari
- Add() har doim goroutine ishga tushishidan oldin chaqirilishi kerak.
- Done() ni unutib qo'yish mumkin — defer bilan ishlatish tavsiya etiladi.
- WaitGroup qayta ishlatilmaydi, ya'ni
Wait()
dan keyin yana Add() chaqirish noto'g'ri hisoblanadi.
Xulosa
WaitGroup Go dasturlash tilida parallel ishlovchi jarayonlarni boshqarishni sodda, lekin kuchli vositasi.