Goroutine导致for循环中的可互换动作

时间:2017-08-01 18:06:35

标签: go goroutine

我很新,我不知道为什么这段代码有这个输出。我知道睡眠会导致新的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

...等

3 个答案:

答案 0 :(得分:0)

  

我知道睡眠会导致新的goroutine在指定的时间内启动另一个线程

这部分不正确!

在只有一个核心的计算机上这是正确的,其中一次只能执行一个线程。

在具有多个内核的计算机上,可以执行与内核并行的多个goroutine。对于并行执行的goroutine,根本没有保证,将在之前或之后执行什么。

答案 1 :(得分:0)

您无法确切地说并发操作的顺序是什么&#34;总是&#34;执行。这是并发的工作原理。如果你想控制执行的顺序,要么不要同时执行,要么使用同步结构(例如互斥,通道)来控制操作的顺序。

答案 2 :(得分:0)

正如其他人所说,无法保证你可以假设执行的顺序。

Go调度程序有一个内部算法,决定如何分配处理器,你可以做很少的事情来控制它而不采用同步(这是正确的方法)。

如果您有兴趣学习如何控制任务之间的同步,请查看sync包,以及channels的工作方式:

https://golang.org/pkg/sync/

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/