Goroutines - 为什么我只能在最后看到并排执行

时间:2014-03-13 19:18:21

标签: multithreading go goroutine

设置

我写了这个小程序,看看执行的线程是如何工作的。这是一个简化版本,您可以在github

上找到完整的版本
func f(from string) { // Bench
    // Loop for i < 40 -> fib(i)
}

func fib(n int64) int { // Something non-linear
    // Fibonacci implementation
}

func main() {

    go f("|||") // <- Should alternate
    go f("---") // <-

    var input string
    fmt.Scanln(&input)
    fmt.Println("done")
}

至于输出,前两行

||| fib( 0 ): 0
--- fib( 0 ): 0

然后全部---

--- fib( 28 ): 317811

此时|||接管并单独进行

||| fib( 29 ): 514229

最后,他们开始“并排”执行,完整的test dump is here

--- fib( 36 ): 14930352
||| fib( 36 ): 14930352
--- fib( 37 ): 24157817
||| fib( 37 ): 24157817
--- fib( 38 ): 39088169
||| fib( 38 ): 39088169
--- fib( 39 ): 63245986
||| fib( 39 ): 63245986

问题

我最初的假设是 - 使用go f()我应该得到一个相对随机的并排执行,但是它会交替出现在不同大小的块中,在29次调用'f()'之后收敛到第一个-第二。为什么会这样?什么可以是更好的测试?

2 个答案:

答案 0 :(得分:3)

这里有很多事情要做。

Go运行时可以自由安排您的goroutine以任何顺序运行,并且可以随时随地运行。所以你应该“并排”执行的假设并不完全有效。此外,很可能您没有设置GOMAXPROCS,这意味着默认情况下运行时使用您的cpu的单个核心。如果你设置GOMAXPROCS&gt; 1,运行时可以选择在多个内核线程上调度goroutine,而内核线程又可以由内核调度,以便在CPU的多个内核上运行。这可能会为您提供您期望的输出。

答案 1 :(得分:2)

除了Seth Hoenig的有用答案之外,并发性和并行性之间存在重要差异。 Goroutines为您提供并发性,这意味着您将描述同时在理论上感到满意的活动,但仅限于抽象意义上。并行性是指事物真正同时发生的时候。你的假设是你会立即看到行动中的并行性。

习惯于使用OS线程的人自然会想到并行性 - 更快的速度通常是所希望的目标。 Goroutines 不是操作系统线程,但它们允许您设计并行系统,这些系统可能实际上也可能不实际并行执行。目标更多的是关于设计清晰度而不是提高性能 ...但你可以通过一点点技巧来实现这两者。

Rob Pike给了an excellent lecture on this,希望我的总结能让他受到公正的待遇。