首页 > 后端开发 > Golang > 为什么附加到并发 Goroutine 中的切片不是线程安全的?

为什么附加到并发 Goroutine 中的切片不是线程安全的?

Linda Hamilton
发布: 2024-11-10 00:49:02
原创
795 人浏览过

Why is Appending to a Slice in Concurrent Goroutines Not Thread-Safe?

并发切片:附加不是线程安全的

问题:

考虑以下代码在 for 循环中使用多个 goroutine 附加到切片:

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()
登录后复制

有时,此代码会在 destSlice 中生成丢失或空白的数据,或者不包含 sourceSlice 中的所有元素。为什么会发生这种情况?

答案:

在 Go 中,当进行并发读/写操作(包括切片)时,所有值都容易受到数据争用的影响。这是由于切片标头(其中包含有关切片的容量和长度的信息)的实现方式所致。

使用 -race 标志运行代码将确认数据争用的存在:

go run -race play.go
登录后复制

解决方案:

为了避免数据竞争并确保附加到切片时的并发安全,应使用同步原语(例如sync.Mutex)来保护写入 destSlice 值:

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()
登录后复制

或者,考虑使用通道来促进并发附加过程。

以上是为什么附加到并发 Goroutine 中的切片不是线程安全的?的详细内容。更多信息请关注PHP中文网其他相关文章!

来源:php.cn
本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
作者最新文章
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板