为了账号安全,请及时绑定邮箱和手机立即绑定

需要 Goroutine 示例说明

需要 Goroutine 示例说明

Go
小怪兽爱吃肉 2021-12-27 17:54:34
我刚刚开始学习 Go 并遵循一个教程,其中包含以下有关 goroutines 的示例:package mainimport (    "fmt"    "runtime")func say(s string) {    for i := 0; i < 5; i++ {        runtime.Gosched()        fmt.Println(s)    }}func main() {    go say("world") // create a new goroutine    say("hello")    // current goroutine}它指出“ runtime.Gosched() 意味着让 CPU 执行其他 goroutines,并在某个时候回来。 ”。示例下方给出了以下输出:helloworldhelloworldhelloworldhelloworldhello但是,当我在我的机器上运行这个例子时,go run我得到helloworldworldworldworldworldhellohellohellohello我的 Go 版本是go version go1.6 darwin/amd64.其实两个结果我都不明白!为什么不只是hello? 按照我的理解,Go 程序在程序的最后一条语句执行后退出,所以我认为在say()作为 goroutine 运行并且它的执行被延迟之后,程序say()作为普通函数执行 next ,打印“hello”然后退出.那么哪个结果是正确的,为什么?
查看完整描述

1 回答

?
慕的地8271018

TA贡献1796条经验 获得超4个赞

第一个输出是由单核机器生成的输出。第二个可以由多核生成。


say是一个内部带有 for 循环的函数,它会迭代 5 次。它确实是一个普通的函数,但其中有一个调用Gosched。是什么Gosched呢,它告诉运行时暂停执行当前够程,而开始另一个等待够程。这称为屈服。


解释第一个输出


这是您可以在单核机器中获得的输出。一步一步来,


go say("world")


在这一步,运行时开始say("world")在单独的 goroutine 上执行调用并继续主 goroutine。但是机器只有一个核心。所以两个 goroutine 不能并行运行。新的 goroutine (say gr A) 必须等到正在运行的 main goroutine (say gr B) 完成或暂停(yields)。所以它等待。主协程开始执行say("hello")


现在在通过运行时的say功能gr B时会遇到runtime.Gosched()


该Gosched呼叫就像暂停。它告诉运行时暂停我并释放另一个正在等待的 goroutine。因此运行时会调度gr A. 它从它等待的地方开始,也就是,


say("world")


现在gr A执行,直到遇到自己的runtime.Gosched(). gr A停顿。gr B醒来并从它离开的地方开始奔跑。后面的语句runtime.Gosched()是打印“hello”。所以打印“你好”。gr B继续并进入其 for 循环的下一次迭代。满足Gosched。暂停。gr A重新启动。打印“世界”。我想你可以看到它是如何进行 5 次的,直到它打印出给定的输出。


解释第二个输出


如果你的机器有多个核心,goroutines 可以并行运行。你的就是你得到的输出。


现在,何时go say("world")调用gr A不必等到gr B完成。它可以立即在另一个内核上启动。所以当Gosched被调用时可能没有等待的 goroutines。如果当前的一个暂停,它将立即在不同的核心上启动。


因此,在多核机器中,您无法保证打印单词的顺序。如果您多次运行该程序,我想您也会看到其他命令。


您可以将 GOMAXPROCs 设置为 1,然后查看程序如何在单核机器上运行。


func main() {

    runtime.GOMAXPROCS(1)


    go say("world") // create a new goroutine

    say("hello")    // current goroutine

}

然后你会看到第一个输出。


查看完整回答
反对 回复 2021-12-27
  • 1 回答
  • 0 关注
  • 121 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信