当前位置: 首页 > 面试题库 >

等待不确定数量的goroutine

云长恨
2023-03-14
问题内容

我有一个代码,其中单个goroutine将触发不确定数量的子goroutine,而后者又将触发更多的goroutine,依此类推。我的目标是等待所有子goroutine完成。

我不知道我将要预先触发的goroutine的总数,所以我不能使用sync.WaitGroup,理想情况下,我不必人为地限制通过channel-
as-
semaphore

模式运行的goroutine的总数。

简短地讲,我想到在每个goroutine中都有一个本地通道或等待组,以作为等待其所有子级的信号灯,但是这导致每个goroutine在所有后代完成时都在占用堆栈空间附近徘徊。

现在,我的想法是在触发goroutine时增加一个原子计数器(在父级中,以避免在父级完成后孩子开始运行时避免虚假地将其设为零),在goroutine完成时将其递减,并定期检查它是否相等归零。

我基本上是在正确的轨道上,还是有一个更优雅的解决方案


问题答案:

我编写了的第一个实现sync.WaitGroup,并且很好地支持了这种情况和其他极端情况。从那以后,德米特里(Dmitry)改进了实施方式,鉴于他的往绩,我敢打赌他只会使它更安全

特别是,您可以相信,如果当前有一个或多个被阻止的Wait呼叫,然后在呼叫Add之前以正增量进行呼叫Done,则不会取消阻止任何先前存在的Wait呼叫。

因此,您绝对可以这样做,例如:

var wg sync.WaitGroup
wg.Add(1)
go func() {
    wg.Add(1)
    go func() {
        wg.Done()
    }()
    wg.Done()
}()
wg.Wait()

自从代码首次集成以来,我实际上在生产中使用了等效逻辑。

作为参考,此内部注释已在第一个实现中提出,并且仍然存在:

// WaitGroup creates a new semaphore each time the old semaphore
// is released. This is to avoid the following race:
//
// G1: Add(1)
// G1: go G2()
// G1: Wait() // Context switch after Unlock() and before Semacquire().
// G2: Done() // Release semaphore: sema == 1, waiters == 0. G1 doesn't run yet.
// G3: Wait() // Finds counter == 0, waiters == 0, doesn't block.
// G3: Add(1) // Makes counter == 1, waiters == 0.
// G3: go G4()
// G3: Wait() // G1 still hasn't run, G3 finds sema == 1, unblocked! Bug.

这描述了在接触实现时要记住的另一种竞争条件,但请注意,即使使用G1进行Add(1) + go f()竞争,该模式也是如此G3

不过,我理解您的问题,因为最近发布的文档中确实有一个令人困惑的陈述,但是让我们查看评论的历史以了解其实际解决的内容。

Russ在修订版15683中发表了评论:

(...)
+// Note that calls with positive delta must happen before the call to Wait,
+// or else Wait may wait for too small a group. Typically this means the calls
+// to Add should execute before the statement creating the goroutine or
+// other event to be waited for. See the WaitGroup example.
func (wg *WaitGroup) Add(delta int) {

拉斯的日志注释指出:

同步:注意在哪里打电话(* WaitGroup)。

修复了问题4762。

如果阅读问题4762,则会发现:

可能值得在sync.WaitGroup文档中添加明确的注释,即在启动包含对Done的调用的go例程之前,应完成对Add的调用。

因此,该文档实际上是针对这样的代码发出警告:

var wg sync.WaitGroup
wg.Add(1)
go func() {
    go func() {
        wg.Add(1)
        wg.Done()
    }()
    wg.Done()
}()
wg.Wait()

这确实是坏的。只是应该对评论进行改进,使其更加具体,并避免您在阅读过程中所产生的似是而非但令人误解的理解。



 类似资料:
  • 我正在尝试将数据库调用移出控制器,以清理并使其可测试。当它们在控制器中时,一切都会顺利进行。我将它们移出控制器,并添加了一个异步,以确保我们等待。否则,我将调用的中的函数。现在,一旦我使用async/await,控制器中的函数就会认为没有用户,因为它没有等待。 有几个关于异步等待的SO问题,但我没有找到一个解决我的问题。我确实验证了返回了我的用户,并添加了控制台日志来显示路径。 节点猫鼬异步等待似

  • 在执行ExecuteSQL函数之后,我会得到未定义的。登录函数使用ExecuteSQL函数用于检查用户是否存在?我在运行这个文件时遇到以下错误。异步等待。 “nodemon”因更改而重启...>[nodemon]开始>未定义>未定义>指示符1

  • 我正试图将图像上传到firebase存储,但调用该函数时,未执行wait以获取url。我错过了什么? 看看这个其他主题,我发现问题可能是“然后”,但我如何设置代码以等待url? 异步/等待/然后飞镖/颤振 谢谢

  • 问题内容: 我编写了量角器自动化测试并遇到了问题。Wait命令实际上并不等待数组元素之一。请参阅以下示例:导航到网页后,我尝试等待第一个元素。 但是测试失败,并显示以下错误:。 错误与定位器类型无关,因为它同时出现在:“ by.repeater”和“ by.css”上。选择器还可以,添加“ sleep”命令后测试通过: 另外,timeout参数也无济于事,它会忽略它并立即失败。 那么问题是如何等待

  • 我正在努力学习如何正确使用async Wait,但我对它有点共同的想法。 在片段中,我试图构建一个对象数组,其中包含我需要的关于我在组件中上传的文件的信息。问题是this.fileInfo中的对象并没有完全等待返回编码图像的promise,而是在我console.logthis.fileInfo时返回此输出: 如您所见,关键图像是一个值未定义的ZoneAwarePromise。你能帮我修一下吗?

  • 问题内容: 我有一个单击按钮并重定向到用户仪表板的测试。发生这种情况时,Webdriver返回: 为了解决这个问题,我将插入到发生重定向的位置,并假设我的CPU使用率很低,这可以解决此问题。但是,2000 ms是任意的并且很慢。是否有类似的东西会等到Angular在重定向页面上加载之前? 问题答案: 您认为这样的事情对您有用吗?最多需要等待10秒,URL才能包含文本“ pageTwo”或您输入的任