Darsliklar Go Lang Select va sync

Go Lang Go Lang Select va sync

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.

selectbir nechta kanaldan qaysi biri birinchi tayyor bo’lsa, o’sha caseni bajaradigan tuzilma. default bo’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.