Gelagat Goroutine: Menyelesaikan Misteri
Kami terjumpa gelagat yang membingungkan dalam kod Go yang disediakan:
package main import ( "fmt" "time" ) type field struct { name string } func (p *field) print() { fmt.Println(p.name) } func main() { data := []field{{"one"}, {"two"}, {"three"}} for _, v := range data { go v.print() } <-time.After(1 * time.Second) }
Timbul persoalan: mengapa kod ini secara konsisten mencetak "tiga" tiga kali, bukannya memaparkan "satu", "dua", dan "tiga" dalam mana-mana susunan?
Memahami Isu
Inti isu terletak pada keadaan perlumbaan halus yang disebabkan oleh penggunaan pembolehubah julat v dalam fungsi goroutine.
Apabila kita menulis v.print(), kita secara berkesan menghantar penuding kepada pembolehubah v, yang merupakan rujukan kepada elemen semasa dalam gelung data julat. Walau bagaimanapun, gelung terus berulang, mengubah suai nilai v.
Apabila goroutine dilaksanakan, ia kebetulan mempunyai nilai akhir v, iaitu "tiga". Ini menghasilkan output tiga "tiga" yang tidak dijangka.
Menyelesaikan Masalah: Pelbagai Pendekatan
Terdapat beberapa cara untuk menyelesaikan isu ini:
1. Menggunakan Perisytiharan Pembolehubah Pendek:
Buat pembolehubah baharu v berskop kepada setiap lelaran gelung:
for _, v := range data { v := v // Short variable declaration to create a new `v`. go v.print() }
2. Menggunakan Sekeping Penunjuk:
Tukar jenis data kepada sekeping penunjuk dan hantar penunjuk individu ke fungsi goroutine:
data := []*field{{"one"}, {"two"}, {"three"}} // Note the '*' for _, v := range data { go v.print() }
3. Menggunakan Alamat Elemen Slice:
Ambil alamat setiap elemen hirisan dan hantar penuding ke fungsi goroutine:
data := []*field{{"one"}, {"two"}, {"three"}} // Note the '*' for i := range data { v := &data[i] go v.print() }
Kesimpulan
Ingat bahawa mengambil alamat pembolehubah julat boleh membawa kepada tingkah laku yang tidak dijangka dalam goroutine jika gelung diubah suai nilai pembolehubah. Dengan menggunakan teknik yang digariskan di atas, kami boleh memastikan setiap goroutine menerima nilai unik dan mengelakkan isu perlumbaan data.
Atas ialah kandungan terperinci Mengapa Kod Go Ini Mencetak 'Tiga' Tiga Kali Daripada 'Satu', 'Dua' dan 'Tiga'?. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!