Skip to content

Buffered va Unbuffered Channel'lar

Go tilida channellar orqali goroutinelar o'rtasida xavfsiz ma’lumot almashinuvi amalga oshiriladi. Channel'lar ikki asosiy turga bo'linadi: unbuffered va buffered. Ularning farqi — ma’lumot yuborish va qabul qilishdagi sinxronlashuv mexanizmida.


Unbuffered Channel

ch := make(chan int)

Unbuffered channelda sender (ma’lumot yuboruvchi) va receiver (ma’lumot qabul qiluvchi) ayni vaqtda mavjud bo'lishi kerak. Aks holda, ulardan biri bloklanadi (kutadi):

  • Sender: ma’lumot yuboradi va receiver tayyor bo'lmaguncha kutadi.
  • Receiver: channeldan o'qishga harakat qiladi va sender hali yubormaguncha kutadi.

Bu xatti-harakatlar orqali goroutinelar orasida to'liq sinxronlashuv ta'minlanadi.

Misol:

package main

func main() {
    ch := make(chan int)
    ch <- 10 // Bu yerda hech kim qabul qilmayapti, shuning uchun deadlock bo'ladi
}

Natija:

fatal error: all goroutines are asleep - deadlock!

Bu xatolik main() ichida hech qanday qabul qiluvchi yo'qligi sababli yuz beradi. Channel yuborilgan qiymatni uzatolmaydi va dastur deadlock ga uchraydi.

Boshqa misol:

package main

import "fmt"

func main() {
    ch := make(chan int)

    go func() {
        ch <- 10
    }()

    val := <-ch
    fmt.Println("Qabul qilindi:", val)
}

Natija:

Qabul qilindi: 10

Bu misolimizda endi qabul qiluvchi goroutine mavjudligi sababli hech qanday deadlock sodir bo'lmadi.

Buffered Channel

Buffered channelda yuborilgan qiymatlar buferda (xotirada) vaqtincha saqlanadi. Channel e’lon qilinayotganda unga bufer hajmi belgilanadi:

ch := make(chan int, 3) // Bu yerda 3 ta qiymatgacha saqlanishi mumkin
  • Sender: bufer to'lmagan bo'lsa, kutmasdan yozadi.
  • Receiver: bufer bo'sh bo'lsa, kutadi.

Misol:

package main

import "fmt"

func main() {
    ch := make(chan int, 2)

    ch <- 1
    ch <- 2

    fmt.Println(<-ch) // 1
    fmt.Println(<-ch) // 2
}

Bu yerda ch <- 1 va ch <- 2 xatolik bermaydi, chunki bufer hajmi 2 ta qiymatni sig'dira oladi.

Yana bir misol ko'ramiz:

package main

import "fmt"

func main() {
    n := 3
    buffered := make(chan int, n)

    // Channelga qiymatlarni yuborish
    for i := 1; i <= 3; i++ {
        buffered <- i
    }

    // channel qiymatlarini qabul qilish
    for i := 1; i <= 3; i++ {
        fmt.Println(<- buffered)
    }
}

Natija:

1
2
3

E'tibor berib qaralsa channelga yuborilgan qiymatlar, qanday tartibda berilgan bo'lsa shu tartibda natija ham olinyapdi. Buning sababi channel FIFO(First In First Out - birinchi kirgan — birinchi chiqadi) tartibida ishlaydi.


Unbuffered channellar katta aniqlikdagi sinxron almashuv uchun foydali, buffered channellar esa yuklama balanslash, log yozish, yoki queue sifatida foydalanishda qo'l keladi.

  • Unbuffered channel — bloklovchi, sinxron usulda ishlaydi.
  • Buffered channel — buferga yozadi, asinxron tarzda ishlaydi.
  • Har ikkisi ham goroutine'lar orasida xavfsiz va tartibli ma’lumot almashuvini ta’minlaydi.
  • Foydalanishdagi maqsadga qarab, to'g'ri turdagi channelni tanlash muhim.