Append 真的是线程安全的吗?
在 Go 中处理对共享资源的并发访问时,同步至关重要。常见的做法是使用 goroutine 将元素附加到切片。然而,append 函数本质上并不是线程安全的。
在所描述的情况下,在循环中创建单独的 goroutine 来附加到切片可能会导致数据不一致。这是因为多个 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()
使用 -race 选项运行此代码将揭示多个数据竞赛。为了防止这些竞争,必须采用诸如互斥体之类的同步机制。下面是使用互斥体的修改后的代码片段:
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 可以处理接收这些值并执行追加操作。
总之,虽然切片元素是不同的变量并且可以在不同步的情况下并发访问,但切片头需要同步以防止并发追加操作期间出现数据争用。
以上是Go 中的 Append 与 Goroutine 一起使用时是线程安全的吗?的详细内容。更多信息请关注PHP中文网其他相关文章!