【问题标题】:Why does this WaitGroup sometimes not wait for all goroutines?为什么这个 WaitGroup 有时不等待所有的 goroutine?
【发布时间】:2016-08-16 16:59:06
【问题描述】:

下面的代码有时会输出 2。为什么等待组不等待所有 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:%v",err)
    }
    <-done
    log.Println("Length: ", len(s.Rash)) 
}`

奇怪的是,我无法通过 main 函数将其输出 2,但是当我使用测试用例时,它有时会输出 2。

【问题讨论】:

    标签: go concurrency


    【解决方案1】:

    您的代码中存在竞争条件。就在这里:

    go func (i int) {
        defer ws.Done()
        // race condition on s.Rash access
        s.Rash = append(s.Rash, i) 
    }(i)
    

    由于所有的goroutines同时访问s.Rash,这可能会导致切片更新被覆盖。尝试使用 sync.Mutex 锁定运行相同的代码以防止这种情况发生:

    // 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)
    

    您可以阅读有关此herehere 的更多信息。

    【讨论】:

    • 我不知道我是怎么错过的——应该休息一下。谢谢,
    • 有时作为使用带切片的互斥锁的替代方案,您可以使用缓冲通道。 play.golang.org/p/CGdz4T2Qn5
    【解决方案2】:

    如果您使用竞赛检测器运行代码

    go test -race .
    

    您将在切片 s.Rash 上找到竞态条件。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-08-26
      • 1970-01-01
      • 2020-03-03
      • 1970-01-01
      • 2013-10-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多