Understanding the Curious Behavior of Goroutines in a Data Race Scenario
In the provided Go code, we create a slice of struct fields called data containing names "one," "two," and "three." The code iterates through the slice, creating goroutines to print each field's name using the print method. However, contrary to expectations, the code repeatedly prints "three" three times, rather than the intended sequence of "one," "two," and "three."
Unveiling the Data Race
This curious behavior stems from a data race, which occurs when multiple goroutines access and potentially modify the same shared data concurrently. In this case, the issue arises from the implicit use of the address of the range variable v when creating the goroutines. When the loop variable v is changed in each iteration, the goroutines end up using its final value, resulting in the constant printing of "three."
Addressing the Data Race
To resolve this issue, we can adopt several approaches:
Creating a New Variable in Each Loop Iteration: Within the loop, we can declare a new variable with the same name as the range variable, effectively creating a new scope for the variable.
for _, v := range data { v := v // Declare a new variable `v` within the loop scope. go v.print() }
Using a Slice of Pointers: Instead of using a slice of struct fields, we can use a slice of pointers to the fields. This ensures that the goroutines receive pointers to individual field elements, preventing data race issues.
data := []*field{ {"one"},{"two"},{"three"} } for _, v := range data { go v.print() }
Passing the Address of the Slice Element: Another alternative is to pass the address of each element in the slice to the goroutine.
for i := range data { v := &data[i] // Take the address of the slice element. go v.print() }
Using Anonymous Functions and Passing Range Variables as Arguments: If the goroutine function is within an anonymous function, we can avoid the issue by passing the range variables as arguments to the function.
for _, v := range data { go func(v field) { // Pass the range variable `v` as an argument. v.print() }(v) }
These approaches ensure that the goroutines have their own copies of the data they need, eliminating the data race and producing the correct output of "one," "two," and "three" in any order.
The above is the detailed content of Why Does My Go Code Print 'Three' Three Times Instead of 'One,' 'Two,' and 'Three' in a Goroutine Data Race?. For more information, please follow other related articles on the PHP Chinese website!