Go 例程子集上的 waitgroup

Par*_*hah 3 multithreading synchronization go

我遇到的情况是,主要的 go 例程将创建“x”个 go 例程。但它只对要完成的“y”( y < x ) go 例程感兴趣。

我本来希望使用 Waitgroup。但 Waitgroup 只允许我等待所有 go 例程。例如,我不能这样做,

1. wg.Add (y)
2 create "x" go routines. These routines will call wg.Done() when finished. 
3. wg. Wait()
Run Code Online (Sandbox Code Playgroud)

当 y+1 go 例程调用 wg.Done() 时,会出现恐慌,因为 wg 计数器变为负值。

我当然可以使用渠道来解决这个问题,但我对 Waitgroup 是否能解决这个问题感兴趣。

Cos*_*age 5

正如Adrian 的回答中所述,sync.WaitGroup是一个简单的计数器,其Wait方法将阻塞,直到计数器值达到零。它的目的是允许您在允许主执行流程继续之前阻止(或加入)多个 goroutine。

\n\n

的界面WaitGroup对于您的用例来说没有足够的表现力,也不是这样设计的。特别是,您不能通过简单地调用wg.Add(y)(where y < x) 来使用它 na\xc3\xafvely。wg.Done第 (y+1)goroutine 的调用将导致恐慌,因为等待组具有负内部值是一个错误。此外,我们不能通过观察内部计数器值来“聪明”。WaitGroup;这会破坏抽象,并且无论如何,其内部状态都不会被导出。

\n\n
\n\n

实施你自己的!

\n\n

您可以根据下面的代码使用一些通道自行实现相关逻辑(游乐场链接)。从控制台观察到,有 10 个 goroutine 启动了,但在两个完成后,我们就在 main 方法中继续执行。

\n\n
package main\n\nimport (\n    "fmt"\n    "time"\n)\n\n// Set goroutine counts here\nconst (\n    // The number of goroutines to spawn\n    x = 10\n    // The number of goroutines to wait for completion\n    // (y <= x) must hold.\n    y = 2\n)\n\nfunc doSomeWork() {\n    // do something meaningful\n    time.Sleep(time.Second)\n}\n\nfunc main() {\n    // Accumulator channel, used by each goroutine to signal completion.\n    // It is buffered to ensure the [y+1, ..., x) goroutines do not block\n    // when sending to the channel, which would cause a leak. It will be\n    // garbage collected when all goroutines end and the channel falls\n    // out of scope. We receive y values, so only need capacity to receive\n    // (x-y) remaining values.\n    accChan := make(chan struct{}, x-y)\n\n    // Spawn "x" goroutines\n    for i := 0; i < x; i += 1 {\n        // Wrap our work function with the local signalling logic\n        go func(id int, doneChan chan<- struct{}) {\n            fmt.Printf("starting goroutine #%d\\n", id)\n            doSomeWork()\n            fmt.Printf("goroutine #%d completed\\n", id)\n\n            // Communicate completion of goroutine\n            doneChan <- struct{}{}\n        }(i, accChan)\n    }\n\n    for doneCount := 0; doneCount < y; doneCount += 1 {\n        <-accChan\n    }\n\n    // Continue working\n    fmt.Println("Carrying on without waiting for more goroutines")\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n
\n\n

避免资源泄漏

\n\n

由于这不会等待 [y+1, ..., x) goroutine 完成,因此您应该在函数中特别小心,doSomeWork以消除或最小化工作无限期阻塞的风险,这也会导致泄漏。尽可能消除无限期阻塞 I/O(包括通道操作)或陷入无限循环的可能性。

\n\n

context当不再需要额外的 goroutine 的结果来让它们退出执行时,您可以使用 a向它们发出信号。

\n