Lompati ke konten utama
Modul 7 · Pelajaran 1 dari 531/50 dalam kursus~12 min
Pelajaran modul (1/5)

Goroutine: paralelisme ringan

goroutine adalah unit eksekusi bersamaan yang dikelola oleh Go waktu proses. Anda meluncurkannya dengan kata kunci go di depan suatu fungsi panggilan:

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

Pernyataan go mengembalikan segera: goroutine dimulai pada paralel dan penelepon terus berjalan.

Mengapa mereka "ringan"

  • Tumpukan awal ~2KB (berkembang secara dinamis, hingga ratusan MB jika diperlukan).
  • Dimultipleks ke sejumlah kecil thread OS pada waktu proses (GOMAXPROCS).
  • Ribuan/jutaan goroutine bersifat rutin; dengan thread OS hal itu tidak mungkin dilakukan.

Secara konseptual ini adalah "api-dan-lupakan secara bersamaan", tetapi dengan semua itu alat idiomatik untuk berkoordinasi (saluran, sync.WaitGroup, context).

utama tidak menunggu

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

Ketika main kembali, proses berakhir: goroutine tidak dapat diperoleh untuk "menyelesaikan pekerjaan mereka", mereka dibunuh begitu saja proses. Sinkronisasi eksplisit diperlukan.

Sinkronisasi: pratinjau

Tiga alat yang akan Anda lihat dalam pelajaran berikutnya:

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

Bug penutupan-dalam-loop "klasik".

Hingga Go 1.21, hal ini sering terjadi:

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

Dari Go 1.22 variabel for baru dibuat di setiap iterasi, jadi bug telah diperbaiki secara default. Di basis kode lama, Anda akan melakukannya masih melihat pola perbaikan:

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! = Utas OS

Aspekgoroutinutas OS
Tumpukan awal~2 KB1–8 MB (dialokasikan di awal)
Penciptaannanodetikmikrodetik
PenjadwalanJalankan runtime (kooperatif)kernel (pencegahan)
Hitungan praktis100K+beberapa ribu

Sebuah thread OS dapat menampung banyak goroutine. Waktu proses bergerak goroutine di seluruh thread bila diperlukan.

Cobalah

Latihan#go.m7.l1.e1
Upaya: 0Memuat…

Luncurkan fungsi salam sebagai goroutine dan tunggu 100 md dengan waktu. Tidur sebelum keluar dari utama.

Memuat editor…
Tunjukkan petunjuk

`go` di depan pemanggilan fungsi meluncurkan goroutine.

Solusi tersedia setelah 3 upaya

Latihan#go.m7.l1.e2
Upaya: 0Memuat…

Luncurkan fungsi anonim sebagai goroutine yang mencetak 'hai'.

Memuat editor…
Tunjukkan petunjuk

Fungsi anonim dipanggil dengan akhiran `()`: `go func(){...}()`.

Solusi tersedia setelah 3 upaya

Quiz#go.m7.l1.e3
Siap

Apa yang terjadi jika `main` keluar sebelum goroutine selesai?

Go
func main() {
  go work()
  // main ritorna immediatamente
}
Pilihan jawaban

Rekap

  • go f() meluncurkan f() secara bersamaan; itu segera kembali.
  • Goroutine = ~2 KB awal, dimultipleks ke beberapa thread OS.
  • main tidak menunggu: Anda memerlukan sinkronisasi (saluran/WaitGroup/konteks).
  • time.Sleep hanya bersifat didaktik, tidak pernah untuk sinkronisasi dalam produksi.
  • Dari Go 1.22 variabel for menjadi "segar" pada setiap iterasi (tidak ada lagi bug "3 3 3").