我很新,我不知道为什么这段代码有这个输出。我知道睡眠会导致新的goroutine在指定的时间内启动另一个线程。我正在尝试按顺序绘制逻辑,看起来“世界”应始终在“你好”之前打印。
package main
import (
"fmt"
"time"
)
func say(s string) {
for i := 0; i < 5; i++ {
time.Sleep(1 * time.Millisecond)
fmt.Println(s, i)
}
}
func main() {
go say("world")
say("hello")
}
实际输出:
world 0
hello 0
hello 1
world 1
world 2
hello 2
hello 3
world 3
world 4
hello 4
预期产出:
world 0
hello 0
world 1
hello 1
world 2
hello 2
...等
答案 0 :(得分:0)
我知道睡眠会导致新的goroutine在指定的时间内启动另一个线程
这部分不正确!
在只有一个核心的计算机上这是正确的,其中一次只能执行一个线程。
在具有多个内核的计算机上,可以执行与内核并行的多个goroutine。对于并行执行的goroutine,根本没有保证,将在之前或之后执行什么。
答案 1 :(得分:0)
您无法确切地说并发操作的顺序是什么&#34;总是&#34;执行。这是并发的工作原理。如果你想控制执行的顺序,要么不要同时执行,要么使用同步结构(例如互斥,通道)来控制操作的顺序。
答案 2 :(得分:0)
正如其他人所说,无法保证你可以假设执行的顺序。
Go调度程序有一个内部算法,决定如何分配处理器,你可以做很少的事情来控制它而不采用同步(这是正确的方法)。
如果您有兴趣学习如何控制任务之间的同步,请查看sync
包,以及channels
的工作方式:
https://tour.golang.org/concurrency/2
但是,我想添加其他人未提及的内容,虽然它不允许您控制执行顺序,但由于问题的性质,可能值得评论。
您可以使用runtime.Gosched
函数来提示调度程序。它会产生处理器,因此其他线程很可能会执行。
https://golang.org/pkg/runtime/#Gosched
如果您添加对Gosched
的呼叫而不是睡觉,在我的测试中,“hello”和“world”更有可能按顺序输出(但同样,不能保证它们会出现随时按随机顺序)。
试试这样:
package main
import (
"fmt"
"runtime"
)
func say(s string) {
for i := 0; i < 5; i++ {
fmt.Println(s, i)
runtime.Gosched()
}
}
func main() {
go say("world")
say("hello")
}
最后,看一下你可能会觉得有趣的这篇文章:
http://container-solutions.com/surprise-golang-thread-scheduling/