我试图了解如何针对以下代码修复此竞争条件。
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甚至开始执行之前就完成了执行。因此,如果我尝试花点时间,它会创建一个竞赛条件。睡眠
答案 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()
以获得预期的输出(仍未提供)。