多个 Goroutine 并发使用时 Append 不是线程安全的吗?
当使用 Goroutine 在循环内并发向切片追加数据时,您可能会遇到不一致的情况,例如缺少或重复的元素。这种情况提出了一个问题:append 函数对于多个 goroutine 并发使用是否不是线程安全的。
答案:数据争用和缺乏线程安全
在 Go 中,没有任何值对于并发读/写是安全的,包括切片(或更具体地说,切片头)。当多个 goroutine 尝试同时修改同一个切片时,会发生数据争用,可能会导致意外行为。
数据争用验证
您可以使用以下命令运行代码 -竞赛选项来确认数据竞赛的存在:
go run -race play.go
解决方案:同步
为了解决这个问题并保证数据的一致性,需要在并发写入元素时同步对切片的访问。这可以使用sync.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()
通过在追加到切片之前获取互斥锁并在之后释放它,可以确保一次只有一个 goroutine 具有写访问权限,从而防止数据损坏。
结论
虽然切片元素表现为不同的变量并且可以修改同时,切片头本质上并不是线程安全的。为了确保安全一致的并发写入操作,在修改 goroutine 内的切片头时采用同步机制(例如互斥锁或通道)至关重要。
以上是Append 函数对于并发 Goroutine 使用是线程安全的吗?的详细内容。更多信息请关注PHP中文网其他相关文章!