去并发和渠道混乱

时间:2013-08-22 21:07:23

标签: concurrency go channel goroutine

我是Go的新手,在理解并发和通道方面遇到了问题。

package main

import "fmt"

func display(msg string, c chan bool){
    fmt.Println("display first message:", msg)
    c <- true
}

func sum(c chan bool){
    sum := 0
    for i:=0; i < 10000000000; i++ {
        sum++
    }
    fmt.Println(sum)
    c <- true
}

func main(){
    c := make(chan bool)

    go display("hello", c)
    go sum(c)
    <-c
}

该计划的输出是:

display first message: hello
10000000000 

但我认为它应该只有一行:

display first message: hello

所以在main函数中,&lt; -c阻塞了它,并等待另外两个go rountines将数据发送到通道。一旦主函数从c接收数据,它就应该继续并退出。

显示和总和同时运行,总和需要更长时间,因此显示应该发送到c并且程序应该在总和完成之前退出...

我不确定我是否理解清楚。有人可以帮我吗?谢谢!

1 个答案:

答案 0 :(得分:4)

程序的确切输出未定义,取决于调度程序。调度程序可以在当前未被阻止的所有goroutine之间自由选择。它试图通过在非常短的时间间隔内切换当前goroutine来同时运行这些goroutine,以便用户感觉到所有事情都是同时发生的。除此之外,它还可以在不同的CPU上并行执行多个goroutine(如果您碰巧有多核系统并增加runtime.GOMAXPROCS)。可能导致您输出的一种情况是:

  1. main创建两个goroutine
  2. 调度程序选择立即切换到其中一个新goroutine并选择display
  3. display打印出消息,并被频道发送(c <- true)阻止,因为还没有接收器。
  4. 调度程序选择运行sum下一步
  5. 总和计算并打印在屏幕上
  6. 调度程序选择不恢复sum goroutine(它已经使用了相当长的时间)并继续display
  7. display将值发送到频道
  8. 调度程序选择运行main next
  9. 主要退出并且所有goroutines都被销毁
  10. 但这只是一种可能的执行顺序。还有很多其他的,其中一些将导致不同的输出。如果您只打印第一个结果并在之后退出程序,则应该使用result chan string并更改main功能以打印fmt.Println(<-result)