go - 如何协调关闭与许多 goroutines
问题描述
说我有一个功能
type Foo struct {}
func (a *Foo) Bar() {
// some expensive work - does some calls to redis
}
在我的应用程序的某个时间点在 goroutine 中执行。其中许多可能在任何给定点执行。在应用程序终止之前,我想确保所有剩余的 goroutine 都完成了它们的工作。
我可以做这样的事情:
type Foo struct {
wg sync.WaitGroup
}
func (a *Foo) Close() {
a.wg.Wait()
}
func (a *Foo) Bar() {
a.wg.Add(1)
defer a.wg.Done()
// some expensive work - does some calls to redis
}
这里假设 Bar 在 goroutine 中执行,其中许多可能在给定时间运行,并且一旦调用 Close 并且在 sigterm 或 sigint 上调用 Close,则不应调用 Bar。
这有意义吗?
通常我会看到 Bar 函数如下所示:
func (a *Foo) Bar() {
a.wg.Add(1)
go func() {
defer a.wg.Done()
// some expensive work - does some calls to redis
}()
}
解决方案
是的,WaitGroup
是正确的答案。根据doc ,您可以WaitGroup.Add
随时使用计数器大于零的值。
请注意,当计数器为零时发生的具有正增量的调用必须在等待之前发生。具有负增量的调用或具有正增量的调用在计数器大于零时开始,可能随时发生。通常这意味着对 Add 的调用应该在创建 goroutine 的语句或其他要等待的事件之前执行。如果重用 WaitGroup 来等待多个独立的事件集,则必须在所有先前的 Wait 调用都返回后发生新的 Add 调用。请参阅 WaitGroup 示例。
Close
但是一个技巧是,在调用之前,您应该始终保持计数器大于零。这通常意味着您应该调用wg.Add
in NewFoo
(或类似的东西)和wg.Done
in Close
。并且为了防止多次调用Done
破坏等待组,你应该Close
换成sync.Once
. 您可能还想防止 newBar()
被调用。
推荐阅读
- c++ - 无法使用 Visual Studio 2019 访问虚幻引擎 4.25 中的头文件
- python - 使用邮箱访问 mbox 中的所有字段
- android - 如何在管理控制台中将设备状态设置为禁用时在设备中显示自定义消息?
- r - 通过节点/顶点查找图中的所有路径
- mongodb - MongoDB 聚合 - 按 _id 分组,然后按另一个字段优先级
- java - 在 Java Swing 的菜单栏上显示图标
- php - 如果订单中有来自 WooCommerce 中某个类别的商品,则向 CC 发送新订单电子邮件
- ios - 如何为 MKAnnotationView 使用自定义 XIB?
- python - jinja2.exceptions.TemplateSyntaxError:226 处的意外字符“”
- ios - 如何使用模式 Xcode 11 显示构建版本