【问题标题】:Golang buffered channel receive data before even sentGolang 缓冲通道在发送之前接收数据
【发布时间】: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。您的读取是从/向通道写入的操作按预期顺序发生,只是您的打印语句似乎出现故障。
  • 您关于发送到缓冲通道的问题与您使用的程序完全不同。

标签: go concurrency channel


【解决方案1】:

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

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

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

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

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

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

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

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

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

【讨论】:

    猜你喜欢
    • 2011-06-08
    • 2014-09-26
    • 2016-08-30
    • 2020-09-23
    • 2015-12-31
    • 2020-09-03
    • 2017-07-22
    • 2011-01-02
    • 2019-10-26
    相关资源
    最近更新 更多