同步。在戈鲁丁开始之前等待组初始化

我在测试中提供了以下代码:


    expected := 10

    var wg sync.WaitGroup

    for i := 0; i < expected; i++ {

        go func(wg *sync.WaitGroup) {

            wg.Add(1)

            defer wg.Done()

            // do something

        }(&wg)

    }

    wg.Wait()

令我惊讶的是,我在运行“去测试”时得到了。当用“去测试-比赛”跑步时,我没有感到恐慌,但测试在稍后的某个时刻失败了。在这两种情况下,尽管有一个wg。Wait(),一个戈鲁廷没有完成执行。panic: Fail in goroutine after TestReadWrite has completed


我做了以下更改,现在测试按预期工作:


    expected := 10

    var wg sync.WaitGroup

    wg.Add(expected)

    for i := 0; i < expected; i++ {

        go func(wg *sync.WaitGroup) {

            defer wg.Done()

            // do something

        }(&wg)

    }

    wg.Wait()

我的疑虑是:


到目前为止,我看到的很多代码都在戈鲁廷内部。为什么它在这个特定情况下会表现得出乎意料?这里似乎正在发生的事情是,一些戈鲁丁似乎完成了运行,并通过了wg。等候(),在其他戈鲁廷开始运行之前。正在使用工作组。添加(1)在戈鲁丁内危险/要避免?如果这通常不是问题,那么究竟是什么导致了这里的问题?wg.Add(1)

添加解决此问题的正确方法是否正确?wg.Add(expected)


汪汪一只猫
浏览 77回答 2
2回答

潇湘沐

根据文档 -等待组等待一组大流子体完成。主戈鲁丁调用 Add 以设置要等待的戈鲁廷数。然后,每个戈鲁丁都会运行并在完成后调用“完成”。同时,等待可用于阻止,直到所有戈鲁丁都完成。所以必须由一个戈鲁廷来调用,它正在引发其他的戈鲁廷,在你的情况下是戈鲁廷。Add()main在第一个代码片段中,您正在调用其他戈鲁廷内部,而不是导致问题的主要戈鲁廷 -Add()expected := 10var wg sync.WaitGroupfor i := 0; i < expected; i++ {&nbsp; &nbsp;go func(wg *sync.WaitGroup) {&nbsp; &nbsp; &nbsp; &nbsp;wg.Add(1) // Do not call Add() here&nbsp; &nbsp; &nbsp; &nbsp;defer wg.Done()&nbsp; &nbsp; &nbsp; &nbsp;// do something&nbsp; &nbsp;}(&wg)}wg.Wait()第二个片段正在工作,因为你正在调用戈鲁廷 -Add()mainexpected := 10var wg sync.WaitGroupwg.Add(expected) // Okayfor i := 0; i < expected; i++ {&nbsp; &nbsp; go func(wg *sync.WaitGroup) {&nbsp; &nbsp; &nbsp; &nbsp;defer wg.Done()&nbsp; &nbsp; &nbsp; &nbsp;// do something&nbsp; &nbsp; &nbsp;}(&wg)}wg.Wait()正在添加工作组。添加(预期)解决此问题的正确方法?您也可以在 for 循环中调用 -wg.Add(1)expected := 10var wg sync.WaitGroupfor i := 0; i < expected; i++ {&nbsp; &nbsp; wg.Add(1) // Okay&nbsp; &nbsp; go func(wg *sync.WaitGroup) {&nbsp; &nbsp; &nbsp; &nbsp;defer wg.Done()&nbsp; &nbsp; &nbsp; &nbsp;// do something&nbsp; &nbsp; &nbsp;}(&wg)}wg.Wait()

手掌心

你的第一种方法恐慌 coz (WaitGroup.Add):“添加”将增量(可能为负数)添加到“等待组”计数器。如果计数器变为零,则释放在 Wait 上阻止的所有大猩猩。如果计数器变为负数,则添加恐慌。......通常,这意味着对 Add 的调用应在创建 goroutine 或其他要等待的事件的语句之前执行当在代码末尾调用 Wait() 时,可能没有一个 goroutine 开始执行 - 因此 WaitGroup 中保存的值为 0。然后,当您的 go 例程执行时,调用 go 例程已经发布。这将导致意想不到的行为,在您的案例中引起恐慌。也许你在那里使用了调用 go 例程中的值。你的第二种方法绝对没问题。您也可以在环路内调用 - 但在块外.Add(1)go func
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go