如何确保向频道发送消息的顺序是正确的

时间:2017-10-13 06:56:28

标签: go

我知道这是错的

func e6() {
    c1 := make(chan struct{}, 1)
    <-c1                  
    go func() {           
        c1 <- struct{}{}
    }()
}

这是对的

func e6() {
    c1 := make(chan struct{}, 1)
    go func() {           //statement1
        c1 <- struct{}{}
    }()
    <-c1        //statement2
}

由于我们不能在右边的例子中假设statement1和statement2的顺序,如果statement2在statement1之前执行会怎样,在这种情况下,右边的例子看起来就像是错误的例子,但为什么这样呢?谢谢你的帮助。

2 个答案:

答案 0 :(得分:2)

实际上,这是在您生成goroutine之后会发生的事情:首先执行goroutine并填充通道,以便您可以立即从中读取(<-c1)。或者首先执行read语句,但由于没有任何内容可以从该通道读取,因此它会等待直到可以读取某些内容(“It blocks”)。现在goroutine调度程序启动,注意到两个goroutine块中的一个并且它“最终”执行另一个goroutine,它填充通道并退出,使阻塞goroutine成为唯一剩余的,以便再次获得执行时间。但是现在通道被填充,可以读取,通道中的值被读取为空,原始goroutine继续,结束功能。

请注意,这有点简化了,你一定要阅读goroutines。

答案 1 :(得分:0)

这是错误的:

func e6() {
    c1 := make(chan struct{}, 1)
    <-c1                  
    go func() {           
        c1 <- struct{}{}
    }()
}

因为执行陷入僵局。通过在主函数线程中调用<-c1,您将阻止来自开放通道的接收。接收将阻塞,直到它从c1收到一些数据,但没有进程在其上发送任何数据。由于代码执行在到达c1语句之前被阻止,因此假设在go上发送的goroutine尚未启动。

在正确的实施中:

func e6() {
    c1 := make(chan struct{}, 1)
    go func() {           //statement1
        c1 <- struct{}{}
    }()
    <-c1        //statement2
}

首先运行哪个语句并不重要。如果statement1首先运行,那么goroutine(在不同的线程中运行)会阻止c1c1 <- struct{}{})上的发送,因为statement2尚未执行,而没有其他进程正在从c1接收数据。这导致整个goroutine阻塞并让执行到statement2将执行的主函数线程(请记住go语句通常不会阻塞)。此时statement2不会阻止,因为其他一些流程(statement1)已准备好通过c1发送数据。因此两个线程都继续完成。

对于statement2首先执行的情况,可以进行类似的推理。