Gülnur ALTAN
Turk Telekom Bulut Teknolojileri
5 min readJul 14, 2023

--

Golang ile İleri Seviye Programlama : Eşzamanlılık ve Paralelizm Nedir ?

Selamlar ,

Bu yazıda Golang dilinde sıkça adını duyduğumuz Eşzamanlılık ve Paralelizm kavramlarını inceleyeceğiz, Gopher’lara keyifli okumalar..

Golang ile Paralel ve Eşzamanlı Programlama Nasıl Yapılır?

Golang (Go), paralel ve eşzamanlı programlama için tasarlanmış bir programlama dilidir. Gelişmiş dil özellikleri ve standart kütüphaneleri, çoklu iş parçacığı (goroutine) kullanımını kolaylaştırır ve paralel programlamayı destekler. Bu makalede, Golang ile paralel ve eşzamanlı programlamanın nasıl yapıldığına dair adımları ele alacağız.

“Eşzamanlılık”(Concurrency) ve “Paralelizm” (Parallelism) ileri seviye Go konuları olarak bilinir. Eşzamanlılık, bir sistemde birden çok işin aynı anda ilerlemesini ifade ederken, paralelizm, bu işlerin aynı anda gerçekleştirildiği anlamına gelir. Go dilinde, bu iki kavramı kullanarak performansı artırabilir ve işleri daha etkin bir şekilde yönetebilirsiniz.

  1. Goroutine’lerle Eşzamanlılık

Golang’da eşzamanlılık, goroutine adı verilen iş parçacıkları (lightweight threads) kullanılarak gerçekleştirilir. Goroutine’ler, main işlevinden bağımsız olarak çalışan iş parçacıklarıdır ve go anahtar kelimesiyle başlatılır. İş parçacığı yönetimi Go derleyicisi tarafından otomatik olarak gerçekleştirilir. Bir fonksiyonu goroutine içinde çalıştırmak için aşağıdaki gibi bir syntax kullanabiliriz:

go functionName()

Örneğin, aşağıdaki kodda, sayHello fonksiyonu bir goroutine içinde çağrılır ve main işlevinin tamamlanmasını beklemeksizin arka planda çalışır:

Bu örnekte, sayHello() fonksiyonu bir rutin olarak çalıştırılır ve main() ayrı bir iş parçacığı olarak devam eder. Bu sayede, sayHello() işlemi eşzamanlı bir şekilde çalıştırılır.

Goroutine’lerin verimli olması, bir programda binlerce veya hatta milyonlarca goroutine’in aynı anda çalışabilmesini sağlar. Bu özellik, büyük ölçekli ve yüksek performans gerektiren uygulamalar için idealdir.

2. Kanallar ile İletişim

Golang’da goroutine’ler arasındaki iletişim, kanal (channel) adı verilen veri yapıları kullanılarak gerçekleştirilir. Kanallar, goroutine’ler arasında veri aktarımını sağlar ve senkronizasyonu kolaylaştırır.

  • Kanal oluşturmak için make() fonksiyonunu kullanabiliriz:

ch := make(chan veriTipi)

  • Gönderici goroutine, kanala veri göndermek için <- operatörünü kullanır:

kanalAdı <- değer

  • Alıcı goroutine, kanaldan veri almak için <- operatörünü kullanır:

değer := <- kanalAdı

Örneğin, aşağıdaki kodda, messages adında bir kanal oluşturuyoruz ve goroutine’ler arasında bir metin iletiyoruz.

Çıktı:

https://bulutbilisimciler.com/

Bu örnekte, anonim bir fonksiyonu goroutine içinde çalıştırarak messages adında bir kanal oluşturuyoruz. Goroutine içinde messages kanalına “Merhaba!” metnini gönderiyoruz. Ana goroutine, msg değişkenine kanaldan gelen veriyi alıyor ve çıktı olarak “Merhaba!” metnini yazdırıyor.

Kanallar, goroutine’ler arasında veri paylaşımı ve senkronizasyon için önemli bir araçtır. Kanal operatörlerini kullanarak veri gönderip alabilir ve goroutine’ler arasında iletişim kurabilirsiniz.

3. Senkronizasyon için WaitGroup

Golang’da senkronizasyonu yönetmek için sync paketinde yer alan WaitGroup kullanılır. WaitGroup, goroutine’lerin tamamlanmasını beklemek için kullanılır.

WaitGroup örneği oluşturmak için sync.WaitGroup kullanılır ve ardından Add() metodu ile beklenen goroutine sayısını belirtebiliriz. Goroutine’ler tamamlandığında Done() metodu çağrılır. Ana goroutine, Wait() metodu ile beklenen tüm goroutine’lerin tamamlanmasını bekler.

Örneğin, aşağıdaki kodda, 3 goroutine’i beklemek için WaitGroup kullanıyoruz:

Çıktı:

https://bulutbilisimciler.com/

Bu örnekte, WaitGroup kullanarak 3 goroutine’i senkronize ediyoruz. Her goroutine başladığında Add() metoduyla beklenen goroutine sayısını artırıyoruz. Goroutine’ler tamamlandığında Done() metodu çağrılıyor ve ana goroutine Wait() metoduyla bekleyerek tamamlanmalarını bekliyor.

sync.WaitGroup kullanarak gorutinlerin senkronizasyonunu sağlandığında, program beklenmedik bir şekilde sonlanmadan önce tüm işlerin bitirilmesini sağlamış oluruz.

Alarm mekanizmasında örnek kullanımı inceleyebilirsiniz.

4. Mutex ile Veri Erişimi

Paralel programlama sırasında birden fazla goroutine’in aynı değişkenlere erişmesi söz konusu olabilir ve bu durum yarış koşullarına (race conditions) yol açabilir. Golang’da yarış koşullarını önlemek için sync paketinde yer alan Mutex kullanılır. Mutex (Mutexes) veya karşılıklı dışlama kilidi, yalnızca bir goroutinenin kilitli bölgeye erişim sağlamasına izin verir.

sync.Mutex örneği oluşturarak bir mutex oluşturabilir ve Lock() ve Unlock() metodlarıyla kilitli bölgeyi belirleyebiliriz. Lock() metodu çağrıldığında, mutex kilitleme işlemi gerçekleştirilir ve sadece çağıran goroutine bölgeye erişebilir. Bölge tamamlandığında, Unlock() metodu çağrılır ve mutex serbest bırakılır.

Örneğin, aşağıdaki kodda, bir mutex kullanarak bir counter(sayaç) değişkenine eşzamanlı erişimi kontrol ediyoruz:

https://bulutbilisimciler.com/courses/go/go-intro-2

Bu örnekte, counter adında bir değişken ve mutex adında bir mutex tanımlıyoruz. increment() fonksiyonunda, mutex kullanarak counter değişkenini güvenli bir şekilde artırıyoruz. Her goroutine, increment() fonksiyonunu çağırarak mutex’i kilitleyip serbest bırakır ve counter değişkenini artırır.

Golang’da Mutex kısaca, paylaşılan verilere eşzamanlı erişimi kontrol etmek için yaygın olarak kullanılan bir mekanizmadır.

5. İşçi Havuzu ile Paralel İşlemler

Bir işçi havuzu (worker pool), belirli bir iş yükünü paralel olarak işlemek için kullanılan bir tasarım desenidir.Genel olarak, görevlendirilmek üzere bekleyen iş parçacıklarından (işçi de denilebilir) oluşmaktadır. Golang’te işçi havuzunu oluşturmak için goroutine’ler ve kanalları kullanabiliriz. Bir kanal, görevleri çalıştırmak için kullanılabilirken, goroutine’ler bu görevleri alır ve işler.

Örneğin, aşağıdaki kodda, bir işçi havuzu oluşturarak 10 adet goroutine’i kullanarak worker ‘ları paralel olarak işleyebiliriz.

Çıktı:

https://bulutbilisimciler.com/

Bu örnekte, worker fonksiyonunu tanımlayarak işçi havuzunu oluşturuyoruz. Her bir worker, tasks kanalından görevleri alıyor ve sonuçları results kanalına gönderiyor. Main işlevinde, tasks kanalına görevleri gönderiyoruz ve ardından worker ’ları başlatıyoruz.

Bu şekilde, görevleri paralel olarak işleyen bir işçi havuzu oluşturmuş oluyoruz. Bu, büyük iş yükleriyle başa çıkmak ve işlem süresini azaltmak için oldukça kullanışlı bir yöntemdir.

Bu makalede, Golang ile paralel ve eşzamanlı programlama konusunda temel adımları ve uygulamaları ele aldık. Golang, goroutine’ler, kanallar, mutex’ler ve görev havuzları gibi güçlü araçlarla paralel ve eşzamanlı programlamayı kolaylaştırır. Bu özellikler, performansı artırmak, iş yükünü dağıtmak ve eşzamanlı işlemleri yönetmek için kullanılabilir.

Paralel ve eşzamanlı programlama, büyük ölçekli ve yüksek performans gerektiren uygulamalar için önemli bir konudur. Golang’un bu konuda sağladığı kolaylık ve destek, geliştiricilere güçlü bir araç seti sunar.

Devamında Bulut Bilişimciler websitesinde yer alan,

Go ile Concurrency (Eşzamanlılık) senaryosuna göz atabilirsiniz 😊

Faydalı Linkler:

https://bulutbilisimciler.com/courses/go

Go ile İlgili Makaleler:

https://medium.com/t%C3%BCrk-telekom-bulut-teknolojileri/go-i%CC%87le-yaz%C4%B1l%C4%B1m-geli%C5%9Ftirme-3ad53d470046

https://medium.com/t%C3%BCrk-telekom-bulut-teknolojileri/go-gin-framework-ile-tam-kapsaml%C4%B1-mikroservis-crud-uygulamas%C4%B1-yazal%C4%B1m-872cc3881be2

https://medium.com/t%C3%BCrk-telekom-bulut-teknolojileri/go-dili-i%CC%87le-minimal-boyutlu-web-service-imagelar%C4%B1-olu%C5%9Fturun-cfd33e67132f

Yararlanılan Kaynaklar:

https://www.yakuter.com/go-dilinde-concurrency/

Karşılıklı Dışlama ,Kilitlenme Kavramı için:

https://bilgisayarkavramlari.com/2011/01/05/birbirini-dislama-mutually-exclusive/

https://tr.wikipedia.org/wiki/Deadlock

--

--