使用单个通道进行Golang并发和阻塞,需要解释

时间:2017-01-23 11:04:04

标签: go concurrency

我正在玩https://tour.golang.org/concurrency/5上显示的代码。我的想法是,我可以通过摆脱退出频道来简化代码,并保持正确的程序行为 - 仅用于学习目的。

这是我得到的代码(为了更好的可读性,简化了它):

package main

import "fmt"
import "time"

func sendNumbers(c chan int) {  
    for i := 0; i < 2; i++ {
        c <- i
    }
}

func main() {
    c := make(chan int)
    go func() {
        for i := 0; i < 2; i++ {
            fmt.Println(<-c)
        }
    }()
    time.Sleep(0 * time.Second)
    sendNumbers(c)
}

在这段代码中,我生成的go例程应该能够在返回之前接收2个数字。我接下来调用的sendNumbers()函数恰好将2个数字发送到通道c。

所以,程序的预期输出是2行:0和1.但是,当我在页面上运行代码时,我得到的只是包含0的单行。

注意

time.Sleep(0 * time.Second) 

虽然我在调用sendNumbers(c)之前故意添加了。如果我将其更改为

time.Sleep(1 * time.Second) 

输出变为预期:

0
1

所以,我对发生的事情感到困惑。有人可以解释发生了什么吗?在调用sendNumbers()之前,无论发送和接收块是多少都不应该通过?

1 个答案:

答案 0 :(得分:2)

在Go中,只要主函数返回,程序就会退出,无论其他goroutine是否仍在运行。如果要确保主函数不会过早退出,则需要一些同步机制。 https://nathanleclaire.com/blog/2014/02/15/how-to-wait-for-all-goroutines-to-finish-executing-before-continuing/
你绝对不必使用同步原语,你也可以只使用通道,可以说这是一种更惯用的方法。