为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

Go
肥皂起泡泡 2021-04-09 17:14:53
我刚接触golang。今天测试通道在Golang中的工作方式时,我感到非常困惑。根据教程:仅当缓冲区已满时才发送到缓冲的通道块。当缓冲区为空时接收块。我的测试程序如下所示:package mainimport "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 0PUT into channel 1goroutine: GET  0goroutine: GET  1goroutine: GET  2PUT into channel 2PUT into channel 3PUT into channel 4PUT into channel 5goroutine: GET  3goroutine: GET  4goroutine: GET  5goroutine: GET  6PUT into channel 6PUT into channel 7PUT into channel 8PUT into channel 9请注意,编号2是从通道中取出的,甚至没有放入通道中。为什么会这样?
查看完整描述

1 回答

?
蝴蝶刀刀

TA贡献1801条经验 获得超8个赞

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

示例输出中的实际执行顺序类似于以下内容:

  1. 编写器例程写入2通道。

  2. 读取器例程2从通道接收。

  3. 读者日常印刷品goroutine: GET  2

  4. 作家的日常打印 PUT into channel 2

您对通道的读取和写入以预期的顺序进行,只是您的打印语句使它看起来不正常。

如果您将作者的操作顺序更改为:

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

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

  1. 执行是并发的,但对stdout的写入是同步的

  2. 每个函数调用和通道发送/接收都为调度程序提供了切换的机会,因此即使使用进行运行GOMAXPROCS=1,它也可以在打印和通道操作(在读取器或写入器中)之间切换goroutines。

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


查看完整回答
反对 回复 2021-04-19
  • 1 回答
  • 0 关注
  • 247 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信