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 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
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:
// 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 propagatiBug penutupan-dalam-loop "klasik".
Hingga Go 1.21, hal ini sering terjadi:
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:
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
| Aspek | goroutin | utas OS |
|---|---|---|
| Tumpukan awal | ~2 KB | 1–8 MB (dialokasikan di awal) |
| Penciptaan | nanodetik | mikrodetik |
| Penjadwalan | Jalankan runtime (kooperatif) | kernel (pencegahan) |
| Hitungan praktis | 100K+ | beberapa ribu |
Sebuah thread OS dapat menampung banyak goroutine. Waktu proses bergerak goroutine di seluruh thread bila diperlukan.
Cobalah
Luncurkan fungsi salam sebagai goroutine dan tunggu 100 md dengan waktu. Tidur sebelum keluar dari utama.
Tunjukkan petunjuk
`go` di depan pemanggilan fungsi meluncurkan goroutine.
Solusi tersedia setelah 3 upaya
Luncurkan fungsi anonim sebagai goroutine yang mencetak 'hai'.
Tunjukkan petunjuk
Fungsi anonim dipanggil dengan akhiran `()`: `go func(){...}()`.
Solusi tersedia setelah 3 upaya
Apa yang terjadi jika `main` keluar sebelum goroutine selesai?
func main() {
go work()
// main ritorna immediatamente
}Rekap
go f()meluncurkan f() secara bersamaan; itu segera kembali.- Goroutine = ~2 KB awal, dimultipleks ke beberapa thread OS.
maintidak menunggu: Anda memerlukan sinkronisasi (saluran/WaitGroup/konteks).time.Sleephanya bersifat didaktik, tidak pernah untuk sinkronisasi dalam produksi.- Dari Go 1.22 variabel
formenjadi "segar" pada setiap iterasi (tidak ada lagi bug "3 3 3").