gokayburuc

GO Fundamentals - Channels

Channels Nedir?

transmission

Bir goroutine’in ürettiği veriyi başka bir goroutine’e aktarmasını sağlar. GO üzerinde concurrency (eşzamanlılık) faaliyetlerini yürütmekte kullanılan bir yapıdır.

Peki eşzamanlılık nedir? Neden ihtiyacımız var?

Concurrency Nedir?

thread

Birden fazla işin aynı zaman aralığında yönetilmesi ve koordine edilmesidir. Thread (iş parçacığı) adı verilen yapıların eş zamanlı olarak çalıştırılması faaliyetlerini içerir.

Concurrency (eşzamanlılık) kavramı için GO Mottosu olarak şu ifadeye dikkat etmek gerekir:

“Belleği paylaşarak iletişim kurma, iletişim kurarak belleği paylaş.”

Yani birden fazla goroutine’in aynı değişken üzerinde doğrudan işlem yapması yerine, verilerin channel aracılığıyla aktarılması bellek açısından daha verimlidir.

GO üzerinde Concurrency Yönetimi

GO üzerinde Concurrency yapıları sadece channels ya da goroutine yapıları ile yürütülmez. Ayrıca sync paketleri de bu noktada kullanılır.

Örnek olarak bir API İstemi (API Request) sırasında aşağıdaki şekilde bir olay akışı olabilir.

Channels Neden Kullanılır?

Birden fazla goroutine içeren bir script yazdığınızı var sayalım. Yani sisteminizde concurrently (eş zamanlı) olarak bu işler nasıl yürütülecek sorusu ortaya çıkar. Burada hafızadaki verilerin yönetimi sırasında doğal yapıya bypass yapılarak, sisteme channels ile mesaj göndererek bizim belirlediğimiz sırayla veri akışı yapılacağını belirtiyoruz.

Diğer kullanım alanları:

Eğer bu yapı olmasaydı ne olurdu? Eğer bu yapı olmasaydı, aynı değişken tekrar tekrar paylaşılır ve goroutine sırasına alınırdı. Böylece birden fazla goroutine aynı değişken üzerinde işlem yapar ve bu da işlem ve zaman kaybına sebep olurdu.

Channels kullanılmadığında goroutine’ler genellikle shared memory üzerinden iletişim kurar. Bu durumda mutex gibi ek senkronizasyon mekanizmalarına ihtiyaç duyulur.

Channel Yazımı

Bir channel oluşturmak için aşağıdaki syntax (sözdizimi) kullanılır.

ch :=make(chan string)

Yukarıda string veri tipinde bir channel oluşturduk. Eğer belirli bir sınır vermek istiyorsak string ifadesinden sonra bir , virgül işareti koyarak, bir limit sayısı belirtmemiz gerekiyor. Bu şekilde elde edeceğimiz ch ifadesi bir buffered channel olur.

Örnek Channels Uygulaması

package main 

import (
	"fmt"
)

func Worker(ch chan string) {
	ch <- "Hello Goroutine!"
}

func main() {
	ch := make(chan string)
	go Worker(ch)
	message := <- ch 
	fmt.Println(message)
}

Burada yazdığımız kodları kısaca inceleyelim.

func Worker(ch chan string) {
	ch <- "Hello Goroutine!"
}

Öncelikle Worker isimli channel yapısında ve string türünde argüman alan bir fonksiyon yazdık. Burada "Hello Goroutine!" ifademizi <- işareti yardımıyla ch isimli bir channel ifadesine atıyoruz.

Burada dikkat ederseniz fonksiyonumuzda bir return ifadesi yok. Çünkü atadığımız değer doğrudan buffer adını verdiğimiz tampon hafıza değerinde tutuluyor. Bu hafıza kısa ve anlık bir hafıza değeridir.

func main() {
	ch := make(chan string)
	go Worker(ch)
	message := <- ch 
	fmt.Println(message)
}

Şimdi main.go isimli bir fonksiyon üzerindeki yapılan işlemleri inceleyelim.

Channel Oluşturma

h := make(chan string)

Öncelikle ch := make(chan string) ifadesi ile ch isimli bir channel değişkeni oluşturduk. Bu değişkende henüz bir değer yok. Değer daha sonra Worker isimli fonksiyondan gelecek.

goroutine Başlatma

go Worker(ch)

Daha Sonrasında ise go Worker(ch) komutu ile Worker isimli fonksiyonumuzu bir goroutine yapısıyla çağırdık. Boş olan ve daha önceden oluşturduğumu ch isimli channel yapısı argüman olarak veriliyor.

Channel'a veri Gönderme

	ch <- "Hello Goroutine!"

Worker isimli fonksiyonun channel içerisinde oluşturduğu "Hello Goroutine!" ifadesini ch isimli string formatında oluşturduğumuz yeni bir channel'a aktarıyoruz. Böylece bu ifade buffer denilen geçici hafızada goroutine ile kullanılmak üzere beklemeye başlıyor.

Channel'dan Veri Alma

message := <-ch

message := <- ch ifadesi ile channel üzerinde gerçekleşen string ifadesi işlemlerini message isimli bir değişkene yazdırıyoruz.

Main goroutine’i channel’daki veriyi alır ve message değişkenine aktarır.

Bu işlem gerçekleştiğinde:

Veriyi Yazdırma

fmt.Println(message)

fmt.Println(message) yapısı ile channel üzerindeki son değeri go routine ile ekrana bastırıyoruz.

Sonsöz ve Değerlendirme

Bu yazıda GO içerisinde channels konusunu basitçe anlatarak, temellerini açıklamış olduk. İlerleyen yazılarda görüşmek üzere...

#go