Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/go/7.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Go sync.Waitgroup不';不要阻止执行_Go - Fatal编程技术网

Go sync.Waitgroup不';不要阻止执行

Go sync.Waitgroup不';不要阻止执行,go,Go,考虑一下这个代码片段 package main import ( "fmt" "sync" "time" ) func main() { wg := new(sync.WaitGroup) nap := func() { wg.Add(1) time.Sleep(2 * time.Second) fmt.Println("nap done") wg.Done() } go

考虑一下这个代码片段

package main

import (
    "fmt"
    "sync"
    "time"
)

func main() {
    wg := new(sync.WaitGroup)
    nap := func() {
        wg.Add(1)
        time.Sleep(2 * time.Second)
        fmt.Println("nap done")
        wg.Done()
    }

    go nap()
    go nap()
    go nap()

    fmt.Println("nap time")
    wg.Wait()
    fmt.Println("all done")
}
运行这样的代码会产生预期的输出:

nap time
nap done
nap done
nap done
all done
time.Sleep(time.Second)
wg.Wait()
fmt.Println("all done")
现在,让我们在
wg.Wait()之前打印第一个标准输出:

输出现在更改为意外值:

all done
在预期的情况下:

nap done
nap done
nap done
all done
上的相同代码确实提供了此输出,而无需省略标准输出


你能给我解释一下,我遗漏了什么吗?

尽管这看起来很神奇,但它有一个合乎逻辑的解释。Go不能保证goroutines的执行顺序。在给定的代码片段中产生了三个goroutine,但实际上有四个:第一个是在执行开始时产生的goroutine

省略标准打印 这个goroutine产生了三个nap函数,并在其计划中继续。它的速度如此之快,以至于在任何生成的goroutine能够调用
wg.Add(1)
之前,它执行了
wg.Wait()
。因此,
wg.Wait()
没有阻止执行,程序结束

wg.Wait()之前打印到标准输出
在这种情况下,程序的执行是不同的,goroutine能够进行
wg.Add(1)
调用,因为主goroutine不像第一种情况那样快。这种行为不能保证,这可以在链接的游乐场示例中看到

这与标准打印无关 以下代码示例将提供相同的预期输出:

nap time
nap done
nap done
nap done
all done
time.Sleep(time.Second)
wg.Wait()
fmt.Println("all done")
fmt.Println()

惯用方式 规则很简单:在生成goroutine之前调用
wg.Add(1)

package main

import (
    "fmt"
    "sync"
    "time"
)

func main() {
    wg := new(sync.WaitGroup)
    nap := func() {
        time.Sleep(2 * time.Second)
        fmt.Println("nap done")
        wg.Done()
    }

    napCount := 3
    wg.Add(napCount)
    for i := 0; i < napCount; i++ {
        go nap()
    }

    wg.Wait()
    fmt.Println("all done")
}
主程序包
进口(
“fmt”
“同步”
“时间”
)
func main(){
wg:=新建(sync.WaitGroup)
nap:=func(){
时间。睡眠(2*时间。秒)
fmt.Println(“nap完成”)
wg.Done()
}
napCount:=3
工作组添加(napCount)
对于i:=0;i
尽管这看起来很神奇,但它有一个合乎逻辑的解释。Go不能保证goroutines的执行顺序。在给定的代码片段中产生了三个goroutine,但实际上有四个:第一个是在执行开始时产生的goroutine

省略标准打印 这个goroutine产生了三个nap函数,并在其计划中继续。它的速度如此之快,以至于在任何生成的goroutine能够调用
wg.Add(1)
之前,它执行了
wg.Wait()
。因此,
wg.Wait()
没有阻止执行,程序结束

wg.Wait()之前打印到标准输出
在这种情况下,程序的执行是不同的,goroutine能够进行
wg.Add(1)
调用,因为主goroutine不像第一种情况那样快。这种行为不能保证,这可以在链接的游乐场示例中看到

这与标准打印无关 以下代码示例将提供相同的预期输出:

nap time
nap done
nap done
nap done
all done
time.Sleep(time.Second)
wg.Wait()
fmt.Println("all done")
fmt.Println()

惯用方式 规则很简单:在生成goroutine之前调用
wg.Add(1)

package main

import (
    "fmt"
    "sync"
    "time"
)

func main() {
    wg := new(sync.WaitGroup)
    nap := func() {
        time.Sleep(2 * time.Second)
        fmt.Println("nap done")
        wg.Done()
    }

    napCount := 3
    wg.Add(napCount)
    for i := 0; i < napCount; i++ {
        go nap()
    }

    wg.Wait()
    fmt.Println("all done")
}
主程序包
进口(
“fmt”
“同步”
“时间”
)
func main(){
wg:=新建(sync.WaitGroup)
nap:=func(){
时间。睡眠(2*时间。秒)
fmt.Println(“nap完成”)
wg.Done()
}
napCount:=3
工作组添加(napCount)
对于i:=0;i
这是一个很好的答案,但可以通过解释OP如何正确地等待goroutine完成而不退出调用goroutine(以及Go中处理数据共享的惯用方法)来做得更好。虽然这是一个很好的信息,但我在任何地方都看不到实际的答案,也就是说,在发送goroutine之前,始终要调用
wg.Add
。是的,如果他在启动goroutine之前调用Add,这会解决问题。感谢您的宝贵意见,我已经更新了答案。这是一个很好的答案,但可以通过解释OP如何正确地等待goroutine完成而不退出调用goroutine(以及Go中处理数据共享的惯用方法)来做得更好。虽然这是一个很好的信息,但我在任何地方都看不到实际的答案,也就是说,在发送goroutine之前,总是要调用
wg.Add
。是的,如果他在启动goroutine之前调用Add,这会解决问题。谢谢你的宝贵意见,我已经更新了答案。