Ana içeriğe geç
Modül 7 · Ders 1 ders 5Kurstaki 31/50~12 min
Modül dersleri (1/5)

Goroutinler: hafif paralellik

goroutine, Go tarafından yönetilen bir eşzamanlı yürütme birimidir çalışma zamanı. Bir işlevin önünde go anahtar sözcüğüyle bir tane başlatırsınız ara:

Go
go greet("Anna")         // chiamata a funzione esistente
go func() {              // funzione anonima
    fmt.Println("hi")
}()

go ifadesi hemen değerini döndürür: goroutine şu şekilde başlar: paraleldir ve arayan kişi devam eder.

Neden "hafif"

  • Başlangıç ​​yığını ~2KB (gerekirse yüzlerce MB'a kadar dinamik olarak büyür).
  • Çalışma zamanına göre az sayıda işletim sistemi iş parçacığına çoğullanmıştır (GOMAXPROCS).
  • Binlerce/milyonlarca goroutin rutindir; işletim sistemi iş parçacıklarıyla bunlar imkansız olurdu.

Kavramsal olarak bu "eşzamanlı ateşle ve unut" yöntemidir, ancak tüm özellikleriyle birlikte koordinasyon için deyimsel araçlar (kanallar, sync.WaitGroup, context).

ana beklemiyor

Go
func main() {
    go func() { fmt.Println("ciao dalla goroutine") }()
    // main esce subito: niente garanzia che la goroutine completi
}

main geri döndüğünde işlem sona erer: goroutinler "işlerini bitirmek" için basitçe öldürülürler süreç. Açık senkronizasyon gerekli.

Senkronizasyon: bir önizleme

Sonraki derslerde göreceğiniz üç araç:

Go
// 1) Channel: la goroutine "segnala" via canale
done := make(chan struct{})
go func() {
    work()
    done <- struct{}{}
}()
<-done   // attendi

// 2) sync.WaitGroup: N goroutine
var wg sync.WaitGroup
wg.Add(1)
go func() { defer wg.Done(); work() }()
wg.Wait()

// 3) context: cancellazione/timeout propagati

"Klasik" döngü içinde kapatma hatası

Go 1.21'e kadar bu sıkça karşılaşılan bir durumdu:

Go
for i := 0; i < 3; i++ {
    go func() { fmt.Println(i) }()  // stampa "3 3 3" su versioni vecchie
}

Go 1.22'den itibaren her birinde for değişkeni yeni oluşturulmuştur. yineleme, böylece hata varsayılan olarak düzeltilir. Daha eski kod tabanlarında şunları yapacaksınız: hala düzeltme modelini görüyorum:

Go
for i := 0; i < 3; i++ {
    i := i           // shadow esplicito
    go func() { fmt.Println(i) }()
}
// oppure passa come argomento:
for i := 0; i < 3; i++ {
    go func(n int) { fmt.Println(n) }(i)
}

Goroutine != İşletim sistemi iş parçacığı

GörünüşGoroutinişletim sistemi iş parçacığı
İlk yığın~2 KB1–8 MB (başlangıçta ayrılır)
Yaratılışnanosaniyemikrosaniye
PlanlamaÇalışma zamanına git (kooperatif)çekirdek (önleyici)
Pratik sayım100.000+birkaç bin

Tek bir işletim sistemi iş parçacığı birçok goroutine ev sahipliği yapabilir. Çalışma zamanı hareketleri Gerektiğinde iş parçacıkları arasında goroutinler.

Deneyin

Egzersiz#go.m7.l1.e1
Denemeler: 0Yükleniyor…

Selamlama işlevini bir goroutine olarak başlatın ve zamanla 100 ms bekleyin. Ana programdan çıkmadan önce uyuyun.

Düzenleyici yükleniyor…
İpucu göster

Bir işlev çağrısının önündeki "go" goroutine'i başlatır.

3 denemeden sonra çözüm mevcut

Egzersiz#go.m7.l1.e2
Denemeler: 0Yükleniyor…

'Merhaba' yazan bir goroutine olarak anonim bir işlev başlatın.

Düzenleyici yükleniyor…
İpucu göster

Anonim bir işlev, sonunda `()`: `go func(){...}()` ile çağrılır.

3 denemeden sonra çözüm mevcut

Quiz#go.m7.l1.e3
Hazır

Bir goroutin tamamlanmadan 'ana' çıkarsa ne olur?

Go
func main() {
  go work()
  // main ritorna immediatamente
}
Cevap seçenekleri

Özet

  • go f() aynı anda f()'ı başlatır; hemen geri döner.
  • Goroutine = ~2 KB başlangıç, birkaç işletim sistemi iş parçacığına çoğullanmış.
  • main beklemez: senkronizasyona ihtiyacınız vardır (kanal/WaitGroup/bağlam).
  • time.Sleep yalnızca öğreticidir, asla üretimde senkronizasyon için değildir.
  • Go 1.22'den itibaren for değişkeni her yinelemede "taze" olur (artık "3 3 3" hatası yoktur).