Is Append Really Thread-Safe?
Synchronization is crucial when dealing with concurrent access to shared resources in Go. A common practice is to append elements to a slice using goroutines. However, the append function is not inherently thread-safe.
In the case described, creating separate goroutines within a loop to append to a slice can lead to data inconsistencies. This is because multiple goroutines writing to the same slice concurrently can result in data races.
To demonstrate this, consider the following code snippet:
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()
Running this code with the -race option will reveal multiple data races. To prevent these races, a synchronization mechanism such as a mutex must be employed. Here's a revised code snippet using a 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()
An alternative solution is to use a channel into which goroutines send the values to be appended. A dedicated goroutine can handle receiving these values and perform the append operation.
In summary, while slice elements are distinct variables and can be accessed concurrently without synchronization, slice headers require synchronization to prevent data races during concurrent append operations.
The above is the detailed content of Is Append in Go Thread-Safe When Used with Goroutines?. For more information, please follow other related articles on the PHP Chinese website!