Golang 缓冲通道在发送之前接收数据

Posted

技术标签:

【中文标题】Golang 缓冲通道在发送之前接收数据【英文标题】:Golang buffered channel receive data before even sent 【发布时间】:2019-01-17 01:02:41 【问题描述】:

我对 golang 很陌生。今天在测试 Golang 中的通道如何工作时,我感到非常困惑。

根据教程:

仅当缓冲区已满时才发送到缓冲通道块。缓冲区为空时接收块。

我的测试程序如下所示:

package main

import "fmt"

func main() 
    ch := make(chan int, 2)

    go func(ch chan int) int 
        for i := 0; i < 10; i++ 
            fmt.Println("goroutine: GET ", <-ch)
        
        return 1
    (ch)

    for j := 0; j < 10; j++ 
        ch <- j
        fmt.Println("PUT into channel", j)
    

我得到这样的输出:

PUT into channel 0
PUT into channel 1
goroutine: GET  0
goroutine: GET  1
goroutine: GET  2
PUT into channel 2
PUT into channel 3
PUT into channel 4
PUT into channel 5
goroutine: GET  3
goroutine: GET  4
goroutine: GET  5
goroutine: GET  6
PUT into channel 6
PUT into channel 7
PUT into channel 8
PUT into channel 9

请注意,数字 2 是在放入频道之前从频道中获取的。为什么会这样?

【问题讨论】:

它没有。您的Println("PUT into channel") 发生在您将其放入通道之后,这意味着在执行该语句之前有机会从通道中读取它。 IE。您的读取是从/向通道写入的操作按预期顺序发生,只是您的打印语句似乎出现故障。 您关于发送到缓冲通道的问题与您使用的程序完全不同。 【参考方案1】:

它没有。您的Println("PUT into channel") 发生在您将其放在通道上之后,这意味着在执行该打印语句之前有机会从通道中读取它。

示例输出中的实际执行顺序大致如下:

    编写器例程将2 写入通道。 Reader 例程从通道接收2。 阅读器例程打印goroutine: GET 2。 编写器例程打印PUT into channel 2

您对通道的读取和写入操作按预期顺序进行,只是您的打印语句使它看起来有问题。

如果您将编写器的操作顺序更改为:

    fmt.Println("PUT into channel", j)
    ch <- j

您可能会看到输出更接近您的预期。然而,它仍然不一定完全代表操作的顺序,因为:

    执行是并发的,但对标准输出的写入是同步的 每个函数调用和通道发送/接收都是调度程序切换的机会,因此即使使用GOMAXPROCS=1 运行,它也可以在打印和通道操作(在读取器或写入器中)之间切换 goroutine。李>

TL;DR:在记录并发操作时不要过多阅读日志消息的顺序。

【讨论】:

以上是关于Golang 缓冲通道在发送之前接收数据的主要内容,如果未能解决你的问题,请参考以下文章

在没有接收器的情况下,是不是可以将数据打开的缓冲通道保留下来?

golang runtime源码阅读 channal实现

golang runtime源码阅读 channal实现

Go笔记(十四):通道 channel

如何在 Golang 中正确处理缓冲通道?

单个通道上的多个接收器。谁得到数据?