ProgramlamaArka Uç Geliştirici

Go'da yürütme akışlarının yönetimi ve zamanlayıcı (scheduler) nasıl uygulanmıştır? Paralel görevler tasarımında dikkate alınması gereken özellikler, iç yapılar ve kısıtlamalar nelerdir?

Hintsage yapay zeka asistanı ile mülakatları geçin

Cevap.

Go, yüksek verimli ağ ve paralel programlar yazmak amacıyla tasarlandığından, yerleşik zamanlayıcıya (scheduler) ve goroutine'lerle basit paralellik yönetimine özel önem verilmiştir. Çoğu dillerde, işletim sistemi (OS) thread'leri doğrudan dil kullanıcıları tarafından yönetilirken, Go'da goroutine'ler daha hafif olup, sabit sayıda sistem thread'i üzerinde binlerce goroutine eş zamanlı çalışabilir.

Sorun: Doğrudan thread yönetimi zordur: bu, hızlı kaynak tüketimi, veri yarışları (data races) ve bellek yönetimi zorluklarına yol açar.

Çözüm: Go, M:N modelini kullanarak, büyük bir goroutine sayısını (M) sınırlı sayıda OS thread'i (N) üzerinde çoklamak için bir zamanlayıcı kullanır. Bu, Go runtime'ının düzeyinde uygulanmış olup, goroutine'lerin çalışmasını otomatik olarak dengeleyip yeniden dağıtır. Programcı sadece goroutine'lerin başlatılması ve senkronizasyonuyla ilgilenir, doğrudan OS thread'leriyle değil.

Kod Örneği:

package main import ( "fmt" "time" ) func worker(id int) { fmt.Printf("Worker %d başlatılıyor ", id) time.Sleep(time.Second) fmt.Printf("Worker %d tamamlandı ", id) } func main() { for i := 0; i < 5; i++ { go worker(i) } time.Sleep(2 * time.Second) }

Anahtar Özellikler:

  • Goroutine'ler OS thread'lerinden daha ucuz, hızlı ve kolay bir şekilde yaratılır, ek bir yönetim gerektirmez.
  • Go zamanlayıcısı, goroutine'lerin düzgün bir şekilde değiştirilmesini sağlamak için runtime içinde özel noktalar kullanarak erken kesme (preemptive) işlemi yapar.
  • GOMAXPROCS, kullanılan OS thread'lerinin sayısını belirler ancak genellikle manuel olarak ayarlamak gerekmez.

Hileli Sorular.

Her goroutine ayrı bir işlemci çekirdeğinde eş zamanlı olarak çalışacak mı?

Hayır. Goroutine'ler çoklanır ve zamanlayıcı, eş zamanlı olarak gerçekleştirilen görevlerin gerçek sayısını belirler.

Belirli goroutine'lerin/thread'lerin yürütmesini manuel olarak yönetmek mümkün mü?

Hayır. Go runtime, doğrudan zamanlama için bir arayüz sağlamaz. Tek istisna, OS thread'lerinin sayısını belirten GOMAXPROCS'dir.

Büyük bir goroutine sayısı, programın otomatik olarak hızlanacağı anlamına mı gelir?

Hayır. Yüksek sayıda eş zamanlı işlem, ek yükler (overhead) yaratabilir: bağlam değiştirmeleri, kaynaklar için rekabet, GC sürelerinin uzaması ve bellek tüketiminin artışı.

Tipik Hatalar ve Antipatternler

  • Limiti olmadan milyonlarca goroutine oluşturma (goroutine leak).
  • Bekleme için time.Sleep kullanma yerine sync.WaitGroup/kanallar kullanımı.
  • Mimariyi anlamadan GOMAXPROCS sayısına aşırı odaklanma.

Gerçek Hayat Örneği

Olumsuz Durum

Mikroservis, gelen istekleri paralel olarak işliyordu, goroutine sayısını sınırlamıyor ve WaitGroup ile bekleme yapmıyordu — sonuç: artan yanıt süresi, data races, öngörülemeyen zaman aşımı.

Artılar:

  • Paralellik eklemenin basitliği;

Eksiler:

  • Bellek limitleri, sızıntılar, karmaşık tanılama.

Olumlu Durum

İşçi yöneticisi, goroutine havuzu aracılığıyla gerçekleştirilir, aynı anda çalışan görev sayısı, bir semafor veya kanallar aracılığıyla sınırlanır. WaitGroup, tüm görevlerin tamamlanmasını doğru bir şekilde bekler.

Artılar:

  • Kontrol edilebilir paralellik, testlerin tekrar edilebilirliği, başarılı ölçeklenebilirlik.

Eksiler:

  • Kısıtlamalar ve senkronizasyon için ek kod gereklidir; deadlock üzerinde testler gereklidir.