英文:
Why is WaitGroup.Wait() hanging when using it with go test?
问题
这是一个简单的示例,展示了我所说的情况。当我运行这段代码时,我得到以下结果:
=== RUN TestWaitGroup
main.go:18: 等待退出信号通道...
main.go:23: 睡眠结束
main.go:25: 关闭退出信号通道
main.go:20: 收到信号
main.go:14: 完成...
main.go:16: 完成!
它会一直挂起,直到超时。如果只使用defer wg.Done()
,会观察到相同的行为。我正在运行go1.18
。这是一个 bug 还是我在这个上下文中没有正确使用 WaitGroup?
英文:
Here's a simple example of what I mean
package main
import (
"sync"
"testing"
"time"
)
func TestWaitGroup(t *testing.T) {
var wg sync.WaitGroup
quitSig := make(chan struct{})
go func(wg sync.WaitGroup, quitChan, chan struct{}) {
defer func() {
t.Log("Done...")
wg.Done()
t.Log("Done!")
}()
t.Log("waiting for quit channel signal...")
<-quitChan
t.Log("signal received")
}(wg, quitSig)
time.Sleep(5*time.Second)
t.Log("Done sleeping")
close(quitSig)
t.Log("closed quit signal channel")
wg.Wait()
t.Log("goroutine shutdown")
}
When I run this, I get the following
=== RUN TestWaitGroup
main.go:18: waiting for quit channel signal...
main.go:23: Done sleeping
main.go:25: closed quit signal channel
main.go:20: signal received
main.go:14: Done...
main.go:16: Done!
Where it just hangs until it timesout. If you just do defer wg.Done()
the same behaviour is observed. I'm running go1.18
. Is this a bug or am I using not using WaitGroups properly in this context?
答案1
得分: 2
两个问题:
-
不要复制
sync.WaitGroup
:根据文档:WaitGroup在第一次使用后不能被复制。
-
在启动工作之前,需要添加
wg.Add(1)
- 与wg.Done()
配对使用
wg.Add(1) // <- 添加这一行
go func(wg *sync.WaitGroup ...) { // <- 指针
}(&wg, quitSig) // <- 使用指针避免复制WaitGroup
https://go.dev/play/p/UmeI3TdGvhg
英文:
Two issues:
-
don't copy
sync.WaitGroup
: from the docs:A WaitGroup must not be copied after first use.
-
you need a
wg.Add(1)
before launching your work - to pair with thewg.Done()
wg.Add(1) // <- add this
go func (wg *sync.WaitGroup ...) { // <- pointer
}(&wg, quitSig) // <- pointer to avoid WaitGroup copy
答案2
得分: 0
你正在传递一个 waitgroup 的副本,所以 goroutine 不会影响外部作用域中声明的 waitgroup。通过以下方式修复:
go func(wg *sync.WaitGroup, quitChan chan struct{}) {
...
}(&wg, quitSig)
在调用 goroutine 时,传递指向 waitgroup 的指针,而不是副本。
英文:
You are passing a copy of the waitgroup, so the goroutine does not affect the waitgroup declared in the outer scope. Fix it by:
go func(wg *sync.WaitGroup, quitChan, chan struct{}) {
...
}(&wg, quitSig)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论