Kanal (Channel) nədir və necə isifadə olunur?

Qısaca Goroutine

Bilirik ki, hər hansı bir proqramın içərisində müxtəlif sayda işi eyni anda görmək lazım gəlir. Bu proses concurrency adlanır. Yəni bizim yazdığımız funksiyalar ardıcıl yox eyni anda işləyəcək. Go proqramlaşdırma dilində concurrency üçün goroutine istifadə olunur. Bu proses çox sadədir. Beləki sadecə go açar sözünü istifadə etmək kifayətdir. Aşağıdakı nümunəyə baxaq.

Burada iki funksiyamız mövcuddur. first() funksiyası 1-dən 10-a qədər, second() funksiyası isə 11-dən 20-yə qədər olan ədədləri log-da bizə göstərəcək. main() funksiyamızda bu funksiyaları çağıraraq qarşısına go açar sözünü yazmışıq. Artıq first()second() funksiyaları ayrı ayrı goroutine-lərdə işləyəcək. Yəni bu funksiyalar eyni anda işləyəcək. Normalda biz funksiyaların qarşısına go yazmasaq, bu zaman əvvəlcə ekranda 1-dən 10-a sonra isə 11-dən 20-yə qədər olan ədədləri görəcəkdik. Ancaq bu vəziyyətdə aşağıdaki nəticəni alırıq.

Kanal ( Channel ) nədir?

Kanal Goroutine-lərin bir biri ilə əlaqə qurması və sinxron olaraq işləməsi üçündür. Bir goroutine hər hansı bir kanala data göndərə və ya kanaldan data oxuya bilər. Bunun üçün go-da "<-" simvolundan istifadə olunur. Kanal yaratmaq üçün make istifadə olunur.

Burada make istifadə edərək myChan adında kanal yaradırıq. Bu kanal vasitəsi ilə göndəriləcək datanın tipini string veririk. Sonra goroutine istifadə edərək kanalın içərisinə "test" datasını atırıq və kanaldakı datanı a adında dəyişənə mənimsədərək aşağıdakı nəticəni alırıq.

İndi gəlin kanalın necə işlədiyinə nəzər yetirək. Kanala data göndərmə və kanaldan datanın alınması prosesi bir birini blok edir. Yəni ki, kanala data göndərən zaman kontrol mexanizmi kanaldan datanın oxunması sətrində blok olunur və həmin kanala data göndərildikdən sonra blok açılır. Yuxarıdakı nümunədə kodun a := <-myChan hissəsində kod blok olunur. Biz goroutine içərisində myChan <- "test" deyib kanala data göndərdikdən sonra blok açılır və fmt.Println(a) işə düşür.

Buffered və Unbeffered kanal

Yuxarıda istifadə olunmuş kanalı unbeffered kanala nümunə göstərmək olar. Unbuffered kanalda sadecə 1 data saxlamaq mümkündür. Buffered kanal isə birdən çox datanı özündə saxlaya bilir.

myChanBuf kanalı içərisində 10 ədəd data saxlaya bilər. Yəni bu kanalın capacity (tutumu) 10-a bərabərdir. Qeyd edək ki, buffered kanal FİFO-dur (First-In-First-Out). Yəni kanala ilk daxil olan data oxumaq üçün ilk çıxan olacaq. Aşağıdakı nümunəyə baxaq.

Burada tutumu 3-ə bərabər olan languageChan adında kanal yaradırıq. Ayrı ayrılıqda iki ədəd goroutine yazırıq. Birinci goroutine ardıcılı olaraq kanala datalar göndərəcək. İkinci goroutine ise bu kanaldakı dataları oxuyaraq bizə aşağıdakı nəticəni verəcək.

Kanallarda For - Range istifadəsi

Yuxarıdakı nümunədə kanaldan dataları oxumaq üçün hər dəfə kanaldakı dataları dayişənə mənimsətdik. Bəs kanaldakı dataları miqdarı çox olarsa? Bu və buna bənzər problemləri aradan qaldırmaq üçün kanaldakı dataları oxuyan zaman for - range istifadə edirik. 

Kanaldakı bloklama əməliyyatı for -  range üçün də eynidir. Bunu dayandırmaq üçün kanala dataları göndərdikdən sonra kanalı close (bağlamaq) lazımdır.

Capacity və Length

Qeyd edim ki, kanala tutumundan çox data göndərildiyi təqdirdə bu zaman "all goroutines are asleep - deadlock!" xətası alırıq.

Bu xəta kanalın capacity (tutumu) ilə bağlı olduğu üçün biz cap() (capacity)len() (length) funksiyaları istifadə edərək buna nəzarət edə bilərik. Capacity kanalı yaradan zaman verdiyimiz onun maksimum tuta biləcəyi datanın miqdarı, length isə cari vəziyyətdə kanalda nə qədər datanın olduğunu göstərir.