Goroutines: Go’da Eşzamanlılık (Concurrency)

Emre Altın
FLO Teknoloji
Published in
4 min readSep 15, 2023

Go programlama dilinin en önemli özelliklerinden biri olan Goroutines, concurrent (eş zamanlı) programlamada büyük bir kolaylık sağlar. Goroutines, hafif iş parçacıkları olarak düşünülebilir ve birçok işlemi aynı anda çalıştırarak programın hızını artırır.

Bu makalede, Go dilinde Goroutines kullanımını detaylı bir şekilde ele alacağız. Hem temel kavramları hem de pratik uygulamaları inceleyerek, Goroutines’in gücünü anlamaya çalışacağız.

Öncelikle concurrency kavramının ne olduğundan bahsederek başlayalım.

Concurrency (Eşzamanlılık)

Concurrency (Eşzamanlılık), aynı anda birden fazla işlemi veya görevi işlemek ve yönetmek anlamına gelir. Bu kavram modern bilgisayarlar ve işletim sistemleri için oldukça önemlidir, çünkü genellikle çoklu çekirdekli işlemciler ve çoklu iş parçacığı desteği sunarlar.

Concurrency kavramını daha iyi anlamak adına şöyle bir örnek verilebilir; bir e-ticaret sitesinin sipariş sisteminde birçok kullanıcı aynı anda sipariş verebilir, ancak concurrency sayesinde sistem her bir siparişi aynı anda işleyebilir ve diğer sipariş süreçlerini ilerletebilir.

Bu kavramı netleştirdiğimize göre Goroutines’in temel özellikleri ile devam edelim:

1. Hafiflik: Goroutines, çok hafif ve az bellek tüketen iş parçacıklarıdır. Birden çok Goroutine aynı anda çalıştırılabilir, bu da büyük uygulamaların daha verimli bir şekilde çalışmasını sağlar.

2. Bağımsızlık: Her bir Goroutine, kendi işini kendisi yönetir ve diğer Goroutine’lerden bağımsız olarak çalışır. Bu, verilerin güvenli bir şekilde paylaşılabilmesini ve eş zamanlı işlem sıkıntılarının engellenmesini sağlar.

3. Kolaylık: Go dilinde goroutines oluşturmak oldukça basittir. Sadece go anahtar kelimesini kullanarak bir işlemi goroutine olarak başlatmak mümkündür.

Örneğin:

go fonksiyonAdi()

İletişim: Goroutines arasında iletişim sağlamak için channels adı verilen bir mekanizma kullanılır. Channels, veri aktarımı ve senkronizasyon için kullanılır ve Goroutines arasındaki iletişimi güvenli bir şekilde yapmanızı sağlar.

Goroutines’in nasıl çalıştırılacağını anlamak için örneklerle birkaç temel senaryo inceleyelim. Go dilinde Goroutines oluşturmak oldukça basittir. Bu özelliği kullanarak aynı anda birden çok işlemi yönetebiliriz.

Aşağıdaki örnekte, Goroutine kullanarak bir fonksiyonu eş zamanlı olarak çalıştıracağız:

package main

import (
"fmt"
"time"
)

func merhaba() {
fmt.Println("Merhaba, bu bir goroutine'den geliyor!")
}

func main() {
go merhaba() // Goroutine oluşturuluyor
time.Sleep(1 * time.Second) // Ana iş parçacığı bir saniye bekliyor
fmt.Println("Main fonksiyonu tamamlandı.")
}

Bu örnekte, merhaba fonksiyonunu bir goroutine içinde çalıştırıyoruz. main fonksiyonu, time.Sleep ile bir saniye boyunca bekliyor, böylece goroutine işini tamamlayabiliyor. Bunu yapmamızın nedeni, Goroutine’in işini bitirmesini beklemek.

Sonuç olarak, “Merhaba, bu bir goroutine’den geliyor!” ve “Main fonksiyonu tamamlandı.” mesajları sırayla görüntülenir.

Aşağıdaki örnekte, birden fazla goroutine’i kullanarak işlemleri aynı anda çalıştıracağız. Birden fazla Goroutine’in işlerini senkronize etmek için sync paketini kullanabiliriz.

sync paketi, Go programlama dilinde concurrent programlamayı desteklemek Goroutine’ler arasındaki senkronizasyonu kolaylaştırmak için kullanılan bir pakettir. Bu aşamada sync paketinin WaitGroup özelliğini kullanacağız. Bu özelliği kullandığımızda çalışan goroutine’in işini bitirmesini bekleyeceğiz.

package main

import (
"fmt"
"sync"
)

func sayiYazdir(n int, wg *sync.WaitGroup) {
defer wg.Done()
fmt.Println(n)
}

func main() {
var wg sync.WaitGroup

for i := 1; i <= 5; i++ {
wg.Add(1)
go sayiYazdir(i, &wg)
}

wg.Wait() // Tüm goroutines'lerin tamamlanmasını bekler
}

Bu örnekte, 1 ila 5 arasındaki sayıları ekrana yazdırmak için beş ayrı goroutine kullandık. sync.WaitGroup ile ana programın erken kapanmamasını sağladık, çünkü Goroutines’ler arka planda çalışıp işlerini bitirene kadar beklememiz gerekiyor.

Goroutines ile Veri Paylaşımı

Goroutines arasında veri iletimi ve senkronizasyon için channels (kanallar) kullanılır. Kanallar, veri akışını düzenler ve goroutines arasında veri iletişimi sağlar. Kanallar, Goroutines’in eş zamanlı olarak çalışmasını ve güvenli bir şekilde veri paylaşılmasını kolaylaştırır.

Kanal oluşturmak ve diğer Goroutines’ler ile iletişim kurmak oldukça basittir.

  1. make(chan T) ile kanal oluşturulur, burada T kanala gönderilecek verinin tipini temsil eder.
  2. kanal <- veri ile kanala veri gönderilir.
  3. veri := <-kanal ile kanaldan veri alınır. Bu işlem, veri gönderilene kadar engellenebilir ve veri alınana kadar bekler.

Kanalların nasıl kullanılacağına dair basit bir örnek yapalım.

func main() {
kanal := make(chan string)

go func() {
kanal <- "Merhaba, bu bir mesaj!"
}()

mesaj := <-kanal
fmt.Println(mesaj)
}

Bu örnekte, make fonksiyonu ile bir kanal oluşturduk. Ardından, Goroutine içinde bu kanala <- işareti ile bir mesaj gönderdik. Ana fonksiyon içinde ise kanaldan alınan mesajı ekrana yazdırmış olduk.

Son olarak; bir web sayfasından veri çekme işlemi gibi gerçek bir senaryoyu ele alalım. Bu sefer, birden fazla web sitesinden aynı anda veri çekme görevini Goroutines kullanarak yapacağız.

package main

import (
"fmt"
"io/ioutil"
"net/http"
"sync"
)

func veriCek(url string, wg *sync.WaitGroup) {
defer wg.Done()

// HTTP GET isteği yap
resp, err := http.Get(url)
if err != nil {
fmt.Printf("Hata: %v\n", err)
return
}
defer resp.Body.Close()

// İstek sonucunda gelen veriyi oku
veri, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Printf("Hata: %v\n", err)
return
}

// Veriyi ekrana yazdır
fmt.Printf("URL: %s, Karakter Sayısı: %d\n", url, len(veri))
}

func main() {
// Çekilecek URL'lerin listesi
urlListesi := []string{
"https://www.example1.com",
"https://www.example2.com",
"https://www.example3.com",
}

// WaitGroup kullanarak goroutines'lerin tamamlanmasını bekleyin
var wg sync.WaitGroup

// Her URL için bir goroutine başlatın
for _, url := range urlListesi {
wg.Add(1)
go veriCek(url, &wg)
}

// Tüm goroutines'lerin tamamlanmasını bekleyin
wg.Wait()

fmt.Println("Tüm veri çekme işlemleri tamamlandı.")
}

Bu örnekte, veriCek adlı bir fonksiyon tanımladık. Her bir url için bu fonksiyonu bir Goroutine içinde çağırdık. Her bir Goroutine, belirtilen url’den veriyi çekti ve veriyi ekrana yazdırdı. sync.WaitGroup kullanarak tüm goroutines’lerin tamamlanmasını bekledik.

Birden fazla url’den veri çekme işlemi, goroutines kullanılarak aynı anda gerçekleştirildiği için işlem süremizi büyük ölçüde azaltmış olduk.

Bu makalede, goroutines’in temel kavramlarını ve kullanımını inceledik. Goroutines kullanarak kodunuzu eşzamanlı hale getirirseniz, Go dilinin sunduğu avantajlardan tam anlamıyla faydalanabilirsiniz. Eşzamanlılık konusunda daha fazla deneyim kazandıkça, programlarınızın daha hızlı ve daha güçlü hale geldiğini göreceksiniz.

--

--

FLO Teknoloji
FLO Teknoloji

Published in FLO Teknoloji

Ayakkabı sektöründe öncü projelere imza atan FLO Teknoloji ekibi, yazılım ve bilişim sektörünün trendleri üzerine makaleleriyle deneyimlerini paylaşıyor.

Emre Altın
Emre Altın