登录
首页 >  Golang >  Go问答

同步:重复利用等待组在先前的等待结果返回前

来源:stackoverflow

时间:2024-02-25 16:42:28 469浏览 收藏

大家好,我们又见面了啊~本文《同步:重复利用等待组在先前的等待结果返回前》的内容中将会涉及到等等。如果你正在学习Golang相关知识,欢迎关注我,以后会给大家带来更多Golang相关文章,希望我们能一起进步!下面就开始本文的正式内容~

问题内容

该代码在多个goroutines中并发运行,以下代码是从生产环境代码中提取的关键相关部分:

func check() {

    .......check condition......

    //skipEnsure and skipNative will not both false here
    var wg sync.WaitGroup
    if !skipEnsure {
        wg.Add(1)
        go func(wg *sync.WaitGroup) {
            defer wg.Done()
            dosomething1()
        }(&wg)
    }
    if !skipNative {
        wg.Add(1)
        go func(wg *sync.WaitGroup) {
            defer wg.Done()
            dosomething2()
        }(&wg)
    }
    wg.Wait() //panic here
}

func worker() {
    ......

    go check()
}

func main() {
    for i:=0;i<32;i++ {
        go worker()
    }
    ch := make(chan any, 0)
    <-ch
}

当 waitgroup 是全局变量时,我可以重现该问题,但不能在提供的代码中重现该问题。在生产环境运行一段时间后会出现panic。


正确答案


如果我理解正确的话,代码看起来像这样:

1  package main
 2  
 3  import (
 4      "sync"
 5      "time"
 6  )
 7  
 8  var wg sync.waitgroup
 9  
10  func work() {
11      wg.add(1)
12      go func(wg *sync.waitgroup) {
13          defer wg.done()
14          time.sleep(1 * time.millisecond)
15          println("one done")
16      }(&wg)
17      wg.add(1)
18      go func(wg *sync.waitgroup) {
19          defer wg.done()
20          time.sleep(2 * time.millisecond)
21          println("two done")
22      }(&wg)
23      wg.wait() //panic here
24  }
25  
26  func main() {
27      for i := 0; i < 10; i++ {
28          go work()
29      }
30      wg.wait()
31      println("done")
32  }

sync.waitgroup 不适用于此类用途。何时调用 wg.add 和 wg.wait 并不明显。如果您尝试使用数据竞争检测器运行它,您可以看到如下内容:

==================
warning: data race
write at 0x0000011707e8 by goroutine 6:
  runtime.racewrite()
      :1 +0x24
  main.work()
      /1.go:23 +0x1b2

previous read at 0x0000011707e8 by goroutine 7:
  runtime.raceread()
      :1 +0x24
  main.work()
      /1.go:11 +0x35

goroutine 6 (running) created at:
  main.main()
      /1.go:28 +0x32

goroutine 7 (running) created at:
  main.main()
      /1.go:28 +0x32
==================
found 1 data race(s)

您可以为每个 goroutine 使用自己的 waitgroup (如您的示例所示)。我无法想象有什么理由反对它。例如,此代码将正常工作,没有任何数据竞争:

package main

import (
    "sync"
    "time"
)

func work() {
    var wg sync.WaitGroup
    wg.Add(1)
    go func(wg *sync.WaitGroup) {
        defer wg.Done()
        time.Sleep(1 * time.Millisecond)
        println("one done")
    }(&wg)
    wg.Add(1)
    go func(wg *sync.WaitGroup) {
        defer wg.Done()
        time.Sleep(2 * time.Millisecond)
        println("two done")
    }(&wg)
    wg.Wait() //panic here
}

func main() {
    var wg sync.WaitGroup
    for i := 0; i < 10; i++ {
        wg.Add(1)
        go func() {
            work()
            wg.Done()
        }()
    }
    wg.Wait()
    println("done")
}

以上就是《同步:重复利用等待组在先前的等待结果返回前》的详细内容,更多关于的资料请关注golang学习网公众号!

声明:本文转载于:stackoverflow 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>