Go并发和通道的混淆

huangapple go评论84阅读模式
英文:

Go concurrency and channel confusion

问题

我是你的中文翻译助手,以下是你提供的代码的翻译:

我刚开始学习Go语言,对并发和通道的理解有些问题。

package main

import "fmt"

func display(msg string, c chan bool){
    fmt.Println("显示第一条消息:", 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
}

程序的输出结果是:

显示第一条消息:hello
10000000000

但是我原以为只会输出一行:

显示第一条消息:hello

所以在main函数中,<-c是阻塞的,它等待另外两个go协程向通道发送数据。一旦main函数从c接收到数据,它应该继续执行并退出。

displaysum函数同时运行,sum函数需要更长的时间,所以display应该先向c发送true,然后程序在sum完成之前退出。

我不确定我是否清楚地理解了这个问题。有人可以帮助我吗?谢谢!

英文:

I'm new to Go and have a problem understanding the concurrency and channel.

package main

import &quot;fmt&quot;

func display(msg string, c chan bool){
    fmt.Println(&quot;display first message:&quot;, msg)
    c &lt;- true
}

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

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

    go display(&quot;hello&quot;, c)
    go sum(c)
    &lt;-c
}

The output of the program is:

display first message: hello
10000000000 

But I thought it should be only one line:

display first message: hello

So in the main function, <-c is blocking it and waits for the other two go rountines to send data to the channel. Once the main function receives the data from c, it should proceed and exit.

display and sum run simultaneously and sum takes longer so display should send true to c and the program should exit before sum finishes...

I'm not sure I understand it clearly. Could someone help me with this? Thank you!

答案1

得分: 4

你的程序的确切输出是未定义的,取决于调度器。调度器可以自由选择当前未被阻塞的所有goroutine之间进行切换。它通过非常短的时间间隔切换当前的goroutine,以使用户感觉所有事情都同时发生。除此之外,如果你的系统是多核的并且增加了runtime.GOMAXPROCS的值,调度器还可以在不同的CPU上并行执行多个goroutine。可能导致你的输出的一种情况是:

  1. main 创建了两个goroutine
  2. 调度器选择立即切换到其中一个新的goroutine,并选择 display
  3. display 打印出消息,并被通道发送操作 (c <- true) 阻塞,因为此时还没有接收者。
  4. 调度器选择运行 sum
  5. 计算并打印出 sum 的结果
  6. 调度器选择不恢复 sum goroutine(它已经使用了相当多的时间),继续执行 display
  7. display 将值发送到通道
  8. 调度器选择运行 main
  9. main 退出,所有的goroutine都被销毁

但这只是一种可能的执行顺序。还有许多其他的执行顺序,其中一些会导致不同的输出。如果你想打印出第一个结果并在程序结束后退出,你应该使用一个 result chan string,并将你的 main 函数改为打印 fmt.Println(<-result)

英文:

The exact output of your program is not defined and depends on the scheduler. The scheduler can choose freely between all goroutines that are currently not blocked. It tries to run those goroutines concurrently by switching the current goroutine in very short time intervals so that the user gets the feeling that everything happens simultanously. In addition to that, it can also execute more than one goroutine in parallel on different CPUs (if you happen to have a multicore system and increase runtime.GOMAXPROCS). One situation that might lead to your output is:

  1. main creates two goroutines
  2. the scheduler chooses to switch to one of the new goroutines immediately and chooses display
  3. display prints out the message and is blocked by the channel send (c &lt;- true) since there isn't a receiver yet.
  4. the scheduler chooses to run sum next
  5. the sum is computed and printed on the screen
  6. the scheduler chooses to not resume the sum goroutine (it has already used a fair amount of time) and continues with display
  7. display sends the value to the channel
  8. the scheduler chooses to run main next
  9. main quits and all goroutines are destroyed

But that is just one possible execution order. There are many others and some of them will lead to a different output. If you want to print just the first result and quit the program afterwards, you should probably use a result chan string and change your main function to print fmt.Println(&lt;-result).

huangapple
  • 本文由 发表于 2013年8月23日 05:07:23
  • 转载请务必保留本文链接:https://go.coder-hub.com/18390852.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定