Rumah >pembangunan bahagian belakang >Golang >Mengapa Kod Go Ini Mencetak 'Tiga' Tiga Kali Daripada 'Satu', 'Dua' dan 'Tiga'?

Mengapa Kod Go Ini Mencetak 'Tiga' Tiga Kali Daripada 'Satu', 'Dua' dan 'Tiga'?

DDD
DDDasal
2024-12-09 13:41:11953semak imbas

Why Does This Go Code Print

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!

Kenyataan:
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn