Middle+
Go'da goroutine planlaması hakkında bilgi verin.
sobes.tech yapay zeka
AI'dan gelen yanıt
Go'daki goroutine planlayıcısı, M:N modelini kullanır; burada M goroutine, N işletim sistemi iş parçacığına haritalanır. Goroutine'leri iş parçacıkları arasında verimli bir şekilde değiştirir ve kesintisiz çoklu görev (multitasking) sağlar, durma noktaları (preemption points) ile.
GPM modelinin temel bileşenleri:
- G (Goroutine): Çalıştırılan kod birimi, hafif iş parçacığı, Go planlayıcısı tarafından yönetilir.
- P (İşlemci): Mantıksal işlemci, yerel kuyruk bağlamını ve mutexler ile planlayıcı gibi kaynakları temsil eder. Varsayılan P sayısı, işlemcinin mantıksal çekirdek sayısı ile belirlenir, ancak
GOMAXPROCSile değiştirilebilir. - M (Makine/İş Parçacığı): İşletim sistemi iş parçacığı, kodu yürütür. M, P ile ilişkilidir ve P'nin yerel kuyruğundan veya küresel kuyruktan goroutine'leri çalıştırır.
Çalışma prensibi:
- Yeni bir goroutine oluşturulur ve kullanılabilir bir P'nin yerel kuyruğuna konur.
- P ile ilişkili M, yerel kuyruktan bir goroutine alır ve çalıştırır.
- Eğer yerel kuyruk boşsa, M diğer P'lerden goroutine çalmaya çalışır.
- P engellendiğinde (örneğin, sistem çağrısı sırasında), ona bağlı M ayrılır ve başka bir M bu P ile ilişkilendirilir. Engellenmiş M, sistem çağrısı tamamlandığında tekrar kullanılabilir.
- Bir goroutine kanal veya mutex üzerinde engellendiğinde, bekleme kuyruğuna alınır ve planlayıcı, aynı M üzerinde başka bir goroutine seçer.
- Planlayıcı, uzun süre çalışan goroutine'leri zorlaştıma (preemption) noktalarıyla durdurmak için periyodik kontroller yapar, böylece diğer goroutine'ler CPU zamanı alabilir.
Preemption noktaları belirli yerlerde ortaya çıkar:
- Fonksiyon/method çağrıları.
- Fonksiyon çağrısı içeren döngüler.
- Bellek tahsisi.
- Senkronizasyon primitive'leri (kanallar, mutexler).
Planlama örneği:
package main
import (
"fmt"
"runtime"
"time"
)
func worker(id int) {
fmt.Printf("Goroutine %d çalışmaya başladı\n", id)
time.Sleep(time.Second) // Çalışmayı taklit et
fmt.Printf("Goroutine %d çalışmayı bitirdi\n", id)
}
func main() {
runtime.GOMAXPROCS(2) // Mantıksal işlemci sayısını ayarla
for i := 1; i <= 5; i++ {
go worker(i) // Goroutine oluştur
}
time.Sleep(3 * time.Second) // Goroutine'lerin tamamlanmasını bekle
fmt.Println("Ana goroutine sona erdi")
}
Bu örnekte, 5 goroutine, 2 mantıksal işlemciye planlanır. Go planlayıcısı, bu goroutine'leri kullanılabilir işletim sistemi iş parçacıkları arasında dağıtacak, yerel ve muhtemelen küresel kuyruklar ile "iş çalma" (work stealing) mekanizmasını kullanacaktır.
Bu yaklaşımın avantajları:
- Ölçeklenebilirlik: Çok çekirdekli sistemlerin verimli kullanımı.
- Düşük maliyet: İşletim sistemi iş parçacıklarına göre hafif goroutine'ler.
- Kullanım kolaylığı: Dile entegre planlama, paralel programlamayı daha erişilebilir kılar.