猿问

需要 Goroutine 示例说明

我刚刚开始学习 Go 并遵循一个教程,其中包含以下有关 goroutines 的示例:


package main


import (

    "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,并在某个时候回来。 ”。示例下方给出了以下输出:


hello

world

hello

world

hello

world

hello

world

hello

但是,当我在我的机器上运行这个例子时,go run我得到


hello

world

world

world

world

world

hello

hello

hello

hello

我的 Go 版本是go version go1.6 darwin/amd64.


其实两个结果我都不明白!为什么不只是


hello

? 按照我的理解,Go 程序在程序的最后一条语句执行后退出,所以我认为在say()作为 goroutine 运行并且它的执行被延迟之后,程序say()作为普通函数执行 next ,打印“hello”然后退出.


那么哪个结果是正确的,为什么?


小怪兽爱吃肉
浏览 122回答 1
1回答

慕的地8271018

第一个输出是由单核机器生成的输出。第二个可以由多核生成。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() {&nbsp; &nbsp; runtime.GOMAXPROCS(1)&nbsp; &nbsp; go say("world") // create a new goroutine&nbsp; &nbsp; say("hello")&nbsp; &nbsp; // current goroutine}然后你会看到第一个输出。
随时随地看视频慕课网APP

相关分类

Go
我要回答