为什么在 go test 中使用 WaitGroup.Wait() 时会挂起?

发布于 2025-01-19 11:20:58 字数 1143 浏览 4 评论 0原文

这是我的意思的一个简单示例

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")
}

当我运行它时,我得到以下内容

=== 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!
    

它只是挂起直到超时。如果您只是defer wg.Done(),则会观察到相同的行为。我正在运行 go1.18。这是一个错误还是我在这种情况下没有正确使用 WaitGroups ?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

毁我热情 2025-01-26 11:20:58

两个问题:


wg.Add(1) // <- add this

go func (wg *sync.WaitGroup ...) { // <- pointer
}(&wg, quitSig) // <- pointer to avoid WaitGroup copy

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 the wg.Done()


wg.Add(1) // <- add this

go func (wg *sync.WaitGroup ...) { // <- pointer
}(&wg, quitSig) // <- pointer to avoid WaitGroup copy

https://go.dev/play/p/UmeI3TdGvhg

呢古 2025-01-26 11:20:58

您正在传递候补组的副本,因此Goroutine不会影响外部范围中声明的候补群。修复它:

    go func(wg *sync.WaitGroup, quitChan, chan struct{}) {
     ...
    }(&wg, quitSig)

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)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文