常规比赛条件解决方案

时间:2019-03-29 10:29:53

标签: go concurrency goroutine

我试图了解如何针对以下代码修复此竞争条件。

sayHello := func() {
    fmt.Println("Hello from goroutine")
}

go sayHello()
time.Sleep(1)

fmt.Println("Hello, playground")

期望:我只是想知道什么是最佳解决方案,应该使用WaitGroup还是有更好的解决方案?

所以我想出了以下解决方案:

var wg sync.WaitGroup
//defer wg.Wait()
sayHello := func() {
    defer wg.Done()
    fmt.Println("Hello from goroutine")
}
wg.Add(1)

go sayHello()
wg.Wait()

fmt.Println("Hello, playground")

但是它会阻塞主goroutine,直到执行代码为止!

同样,如果我使用defer wg.Wait(),则输出将不同! https://play.golang.org/p/_xkLb7HvNF8

种族条件我的意思是go sayHello()从未执行过,因为主函数将在goroutine甚至开始执行之前就完成了执行。因此,如果我尝试花点时间,它会创建一个竞赛条件。睡眠

1 个答案:

答案 0 :(得分:3)

您的代码中没有race condition

第一个问题

  

但是它会阻塞主goroutine,直到执行代码为止!

您正在sayHello通话之后立即使用:

wg.Wait()

这将阻塞您的代码,并等待直到执行goroutine。因此,go sayHello()将始终在"Hello from goroutine"之前打印"Hello, playground"

请参阅文档here

  

等待直到WaitGroup计数器为零为止。

第二个问题

  

同样,如果我使用defer wg.Wait(),输出将有所不同!

是的,在这种情况下,wg.Wait()将在退出主功能之前执行。这意味着sayHello()将在之前或之后"Hello from goroutine"之前打印"Hello, playground"-这取决于 Go调度程序

详细了解defer here

  

defer语句将函数调用推送到列表上。周围函数返回后,将执行保存的呼叫列表。 Defer通常用于简化执行各种清理操作的功能。

更新

与其他使用渠道的解决方案相比,建议使用WaitGroup。您应该在正确的位置使用wg.Wait()以获得预期的输出(仍未提供)。