将超时设置为WaitGroup.Wait()的惯用方式是什么?
我之所以想这么做,是为了保护我的"调度程序"不可能永远等待一个错误的"工作人员".这就引出了一些哲学问题(例如,一旦系统中出现了错误的工作人员,该系统如何可靠地继续工作?),但我认为这超出了这个问题的范围.
我会提供一个答案.现在我已经把它写下来了,它看起来并没有那么糟糕,但它仍然感觉比它应该的更复杂.我想知道是否有更简单、更惯用的方法,或者甚至是一种不使用waitgroup的替代方法.
好的.
将超时设置为WaitGroup.Wait()的惯用方式是什么?
我之所以想这么做,是为了保护我的"调度程序"不可能永远等待一个错误的"工作人员".这就引出了一些哲学问题(例如,一旦系统中出现了错误的工作人员,该系统如何可靠地继续工作?),但我认为这超出了这个问题的范围.
我会提供一个答案.现在我已经把它写下来了,它看起来并没有那么糟糕,但它仍然感觉比它应该的更复杂.我想知道是否有更简单、更惯用的方法,或者甚至是一种不使用waitgroup的替代方法.
好的.
大多数情况下,您发布的below个解决方案都是最好的解决方案.改善它的几个小贴士:
defer
语句来表示完成,即使函数突然终止,它也会执行.WaitGroup
,只发送一个值,或在作业(job)完成时关闭通道(与select
语句中使用的通道相同).timeout := time.Second
.例如,指定2秒为:timeout := 2 * time.Second
.您不需要转换,time.Second
已经是time.Duration
类型,将其乘以像2
这样的无类型常量也会得到time.Duration
类型的值.我还将创建一个包装此功能的助手/实用程序函数.请注意,必须将WaitGroup
作为指针传递,否则副本将不会收到WaitGroup.Done()
次调用的"通知".比如:
// waitTimeout waits for the waitgroup for the specified max timeout.
// Returns true if waiting timed out.
func waitTimeout(wg *sync.WaitGroup, timeout time.Duration) bool {
c := make(chan struct{})
go func() {
defer close(c)
wg.Wait()
}()
select {
case <-c:
return false // completed normally
case <-time.After(timeout):
return true // timed out
}
}
使用它:
if waitTimeout(&wg, time.Second) {
fmt.Println("Timed out waiting for wait group")
} else {
fmt.Println("Wait group finished")
}
在Go Playground号公路上试试吧.