Concurrent Programming with Go — 2

Hande Ebrar Gunesdogdu
3 min readOct 18, 2022

Bu yazıda serinin ilk yazısında bahsettiğim concurrency ve goroutine’in devamı olan sync package’tan bahsedeceğim.

Keyifli okumalar! ✌️

Goroutine’lerin birbirleriyle koordine olarak çalışabilmelerini sağlayacak built-in bir mekanizmaları yoktur. Aynı adres alanında çalışabilirler, bu nedenle shared-memory’e erişimin senkronize edilmesi gerekir. Buna bir çözüm olarak: sync package

sync package

Mutual exclusion lock gibi temel senkronizasyon öğelerini içererek Goroutine’lerin birlikte çok daha sorunsuz çalışmasına imkan sağlar.

Concurrency’nin beraberinde getirdiği bazı problem vardır:

  1. Task’ların senkronizasyonunu sağlayabilmek
  2. Shared-memory’e aynı anda birçok yerden erişilmesi

sync package’da bu problemlere çözüm olacak imkanlar mevcut:

  1. waitGroup, bir Goroutine koleksiyonunun işlemlerinin bitmesini bekler.

main goroutine, Add() fonksiyonuyla beklenecek goroutine sayısını bildirir. Ardından, goroutine’lerin her biri çalışır ve bittiğinde Done() fonksiyonunu çağırır. Aynı zamanda Wait(), tüm goroutine’ler bitene kadar kodun belirli kısmını bloklamak için kullanılabilir.

waitGroup’u fonksiyona parametre olarak geçmek istersek mutlaka bir pointer kullanmalıyız. Çünkü, program mantığını bozacak olan counter’ı etkileyebilir.

2. mutex, A Mutual Exclusion Lock

mutex’in ne işe yaradığını bir örnekle açıklamaya çalışalım: Örneğin belirli aralıklarla güncellenen ve çok sayıda get yapılan datalarınız var. Her seferinde veri tabanından okuma işlemi yapmak yerine bu dataları cache’e yazdınız. Bu cache’e her 30 dakikada 1 write işlemi yapılıyor ve sürekli read işlemi ile farklı servislerden datalar get ediliyor. Peki write işlemi tamamlanmadan read işlemi de aynı ana denk gelirse ne olacak?

go run — — race .

mutex, race condition oluşmasını önlemek için, bir process işlenirken diğer process’lerin critical-section dediğimiz paylaşılan kaynaklar içeren kod parçasına erişimini engelleyen mutual exclusion lock yapısıdır.

Temel olarak: lock the mutex → access the memory → unlock the mutex şeklinde çalışır. Aşağıda Lock() ile ortak belleğe erişen kod parçasına başka bir process’in girmesini engelledik. İşlem bittikten sonra Unlock() ile buranın tekrar erişilebilir olmasını sağladık.

Gerçek uygulamalarda read ve write işlem sayıları eşit olmayabilir. Genellikle read işlem sayısı, write işlem sayısından daha fazladır. Bu gibi durumlarda mutex’i daha verimli kullanabilmek için:

RWMutex (Read/Write Mutex): Read process’leri birbirlerini beklemek zorunda değil, sadece lock’lanmış write process’lerinin tamamlanmasını beklerler.

RLock() / RUnlock() → read process’leri için

Lock() / Unlock() → write process’leri için

Bu yazıda goroutine’lerin birbiriyle senkronizasyonunu sağlamak için temel ilkeler sunan sync package’ı inceledik. Buradaki ilkelerin uygulamalarımızdaki goroutine’lerin yönetimi konusunda zayıf kalabileceğini belirtmek isterim. Serinin bir sonraki yazısında sync package’a alternatif olarak neler kullanabiliriz buna deyineceğim. Tekrar buluşmak dileğiyle! 🌟

References and Links

⭐ Concurrency in Go, Katherine Cox-Buday

Concurrent and Parallel Programming, Joe Armstrong

Golang Concurrency

Concurrency

⭐ Concurrent Programming with Go, By Mike Van Sickle

⭐ Go Course: Sync Package, Karan Pratap Singh

--

--