Rumah > pembangunan bahagian belakang > Golang > Mengapakah fungsi `tambah` tidak selamat benang untuk akses serentak dalam Go?

Mengapakah fungsi `tambah` tidak selamat benang untuk akses serentak dalam Go?

Patricia Arquette
Lepaskan: 2024-11-10 03:50:02
asal
374 orang telah melayarinya

Why is `append` function not thread-safe for concurrent access in Go?

Tambah Fungsi: Tidak Selamat Benang untuk Akses Serentak

Apabila menggunakan goroutine secara serentak untuk menambahkan elemen pada kepingan dalam gelung for, anomali dalam data boleh timbul. Data yang hilang atau kosong mungkin muncul dalam kepingan terhasil, menunjukkan perlumbaan data yang berpotensi.

Ini berlaku kerana dalam Go, tiada nilai yang secara semula jadi selamat untuk membaca dan menulis serentak. Kepingan, yang diwakili oleh pengepala kepingan, tidak terkecuali. Kod yang diberikan mempamerkan perlumbaan data kerana akses serentak:

destSlice := make([]myClass, 0)

var wg sync.WaitGroup
for _, myObject := range sourceSlice {
    wg.Add(1)
    go func(closureMyObject myClass) {
        defer wg.Done()
        var tmpObj myClass
        tmpObj.AttributeName = closureMyObject.AttributeName
        destSlice = append(destSlice, tmpObj)
    }(myObject)
}
wg.Wait()
Salin selepas log masuk

Untuk mengesahkan kehadiran perlumbaan data, laksanakan arahan berikut:

go run -race play.go
Salin selepas log masuk

Output akan memaklumkan anda tentang perlumbaan data :

WARNING: DATA RACE
...
Salin selepas log masuk

Menyelesaikan Isu Konkurensi

Untuk menyelesaikan isu ini, lindungi akses tulis kepada destSlice dengan menggunakan penyegerakan.Mutex:

var (
    mu        = &sync.Mutex{}
    destSlice = make([]myClass, 0)
)

var wg sync.WaitGroup
for _, myObject := range sourceSlice {
    wg.Add(1)
    go func(closureMyObject myClass) {
        defer wg.Done()
        var tmpObj myClass
        tmpObj.AttributeName = closureMyObject.AttributeName
        mu.Lock()
        destSlice = append(destSlice, tmpObj)
        mu.Unlock()
    }(myObject)
}
wg.Wait()
Salin selepas log masuk

Sebagai alternatif, pertimbangkan untuk menggunakan saluran untuk mengendalikan lampiran secara tidak segerak:

var (
    appendChan = make(chan myClass)
    destSlice  = make([]myClass, 0)
)

var wg sync.WaitGroup
for _, myObject := range sourceSlice {
    wg.Add(1)
    go func(closureMyObject myClass) {
        defer wg.Done()
        var tmpObj myClass
        tmpObj.AttributeName = closureMyObject.AttributeName
        appendChan <- tmpObj
    }(myObject)
}
go func() {
    for {
        tmpObj := <-appendChan
        destSlice = append(destSlice, tmpObj)
    }
}()
wg.Wait()
Salin selepas log masuk

Atas ialah kandungan terperinci Mengapakah fungsi `tambah` tidak selamat benang untuk akses serentak dalam Go?. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

sumber:php.cn
Kenyataan Laman Web ini
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
Artikel terbaru oleh pengarang
Tutorial Popular
Lagi>
Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan