Select — bir nechta kanalni bir vaqtda kuzatish uchun ishlatiladigan boshqaruv tuzilmasi, switchning kanallar uchun muqobili. sync paketi esa channel yetarli bo’lmagan hollarda umumiy xotirani to’g’ridan-to’g’ri, xavfsiz himoyalash vositalarini beradi.
select — bir nechta kanaldan qaysi biri birinchi tayyor bo’lsa, o’sha
caseni bajaradigan tuzilma.defaultbo’limi — hech qaysi kanal tayyor bo’lmasa, bloklanmasdan darhol ishga tushadi.
select — birinchi tayyor kanalni tanlash
package main
import "fmt"
func main() {
kanal1 := make(chan string, 1)
kanal2 := make(chan string, 1)
kanal1 <- "kanal1dan xabar"
select {
case xabar1 := <-kanal1:
fmt.Println(xabar1)
case xabar2 := <-kanal2:
fmt.Println(xabar2)
default:
fmt.Println("hech narsa kelmadi")
}
}
kanal1dan xabar
kanal1da qiymat tayyor edi, kanal2da esa yo’q — select mos caseni tanladi. Agar ikkala kanal ham bir vaqtda tayyor bo’lsa, Go ular orasidan tasodifiy birini tanlaydi — bu qaysidir kanalning doim ustunlik qilishining oldini oladi.
default — bloklanmasdan tekshirish
Hech qaysi kanal tayyor bo’lmasa va default mavjud bo’lsa, select kutib turmasdan darhol defaultga o’tadi:
package main
import "fmt"
func main() {
kanal := make(chan string)
select {
case xabar := <-kanal:
fmt.Println(xabar)
default:
fmt.Println("hech narsa kelmadi")
}
}
hech narsa kelmadi
kanalda hech qachon qiymat kelmaydi (uni to’ldiruvchi goroutine yo’q), lekin default borligi sabab dastur abadiy bloklanib qolmadi — darhol “hech narsa kelmadi” deb javob qaytardi. defaultsiz select bunday holatda cheksiz kutib qolgan bo’lardi.
sync.Mutex — umumiy xotirani himoyalash
Bir nechta goroutine bitta umumiy o’zgaruvchini bir vaqtda o’zgartirsa, natija buzilishi (race condition) mumkin. sync.Mutex bir vaqtning o’zida faqat bitta goroutine’ga kirishga ruxsat beradi:
package main
import (
"fmt"
"sync"
)
type Hisoblagich struct {
mu sync.Mutex
qiymat int
}
func (h *Hisoblagich) Oshir() {
h.mu.Lock()
defer h.mu.Unlock()
h.qiymat++
}
func main() {
h := Hisoblagich{}
var wg sync.WaitGroup
for i := 0; i < 1000; i++ {
wg.Add(1)
go func() {
defer wg.Done()
h.Oshir()
}()
}
wg.Wait()
fmt.Println(h.qiymat)
}
1000
h.mu.Lock() — boshqa goroutine shu qulf ochiq bo’lguncha kuta turadi. defer h.mu.Unlock() — funksiyadan chiqishda qulfni albatta bo’shatadi. Aynan shu tufayli 1000 ta goroutine bir vaqtda qiymat++ qilsa ham, hech qanday yangilanish “yo’qolib qolmaydi” va natija aniq 1000 bo’ladi. Mutexsiz, xuddi shu kod ba’zan 1000dan kamroq natija berishi mumkin edi — bir nechta goroutine bir xil qiymatni bir vaqtda o’qib, bittasining yangilanishi yo’qolib ketishi orqali.
Qachon channel, qachon Mutex
| Vosita | Qachon mos keladi |
|---|---|
| Channel | goroutine’lar orasida ma’lumot uzatish, ishni navbatga qo’yish |
| Mutex | bir nechta goroutine umumiy holatni (masalan, hisoblagich, keshni) birga o’qib-yozganda |
Go jamoasining mashhur qoidasi: “Xotirani almashish orqali gaplashmang, gaplashish orqali xotira almashing” — imkon qadar channel’ga tayaning, Mutex esa umumiy holatni himoyalash chindan zarur bo’lgandagina ishlatiladi.