英文:
Why does this WaitGroup sometimes not wait for all goroutines?
问题
下面的代码有时会输出2。为什么等待组(wait group)没有等待所有的goroutine完成?
type Scratch struct {
//sync.RWMutex
Itch []int
}
func (s *Scratch) GoScratch(done chan bool, j int) error {
var ws sync.WaitGroup
if len(s.Itch) == 0 {
s.Rash = make([]int, 0)
}
for i := 0; i < j; i++ {
ws.Add(1)
go func (i int) {
defer ws.Done()
s.Rash = append(s.Rash, i)
}(i)
}
ws.Wait()
done <- true
return nil
}
func main() {
done := make(chan bool, 3)
s := &Scratch{}
err := s.GoScratch(done, 3)
if err != nil {
log.Println("Error: ", err)
}
<-done
log.Println("Length: ", len(s.Rash))
}
奇怪的是,我无法通过main函数输出2,但是当我使用一个测试用例时,有时会输出2。
英文:
The code below outputs 2 sometimes. Why isn't the wait group waiting for all the goroutines to complete ?
type Scratch struct {
//sync.RWMutex
Itch []int
}
func (s *Scratch) GoScratch(done chan bool, j int) error {
var ws sync.WaitGroup
if len(s.Itch) == 0 {
s.Rash = make([]int, 0)
}
for i := 0; i < j; i++ {
ws.Add(1)
go func (i int) {
defer ws.Done()
s.Rash = append(s.Rash, i)
}(i)
}
ws.Wait()
done<- true
return nil
}
func main() {
done := make(chan bool, 3)
s := &Scratch{}
err := s.GoScratch(done, 3)
if err != nil {
log.Println("Error:%v",err)
}
<-done
log.Println("Length: ", len(s.Rash))
}`
Strangely i can't get it to output 2 with a main function but when I use a test case it outputs 2 sometimes.
答案1
得分: 10
你的代码中存在竞态条件。它就在这里:
go func (i int) {
defer ws.Done()
// 在 s.Rash 访问上存在竞态条件
s.Rash = append(s.Rash, i)
}(i)
由于所有的 goroutine 都同时访问 s.Rash
,这可能导致切片的更新被覆盖。尝试使用 sync.Mutex
运行相同的代码来防止这种情况发生:
// 创建一个全局互斥锁
var mutex = &sync.Mutex{}
// 使用互斥锁来防止竞态条件
go func (i int) {
defer ws.Done()
defer mutex.Unlock() // 确保互斥锁解锁
// 在访问资源之前锁定它
mutex.Lock()
s.Rash = append(s.Rash, i)
}(i)
英文:
There is a race condition in your code. It is right here:
go func (i int) {
defer ws.Done()
// race condition on s.Rash access
s.Rash = append(s.Rash, i)
}(i)
Since all the goroutines access s.Rash
concurrently, this may cause the slice updates to be overwritten. Try running the same code with sync.Mutex
locking to prevent this:
// create a global mutex
var mutex = &sync.Mutex{}
// use mutex to prevent race condition
go func (i int) {
defer ws.Done()
defer mutex.Unlock() // ensure that mutex unlocks
// Lock the resource before accessing it
mutex.Lock()
s.Rash = append(s.Rash, i)
}(i)
答案2
得分: 6
如果你使用竞争检测器运行你的代码:
go test -race .
你会发现在切片s.Rash
上存在竞争条件。
英文:
If you run your code with race detector
go test -race .
you will find out race condition on slice s.Rash
.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论