我刚接触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语句之前,有机会从通道中读取它。
示例输出中的实际执行顺序类似于以下内容:
编写器例程写入
2
通道。读取器例程
2
从通道接收。读者日常印刷品
goroutine: GET 2
。作家的日常打印
PUT into channel 2
您对通道的读取和写入以预期的顺序进行,只是您的打印语句使它看起来不正常。
如果您将作者的操作顺序更改为:
fmt.Println("PUT into channel", j) ch <- j
您可能会看到输出更接近您的期望。但是,它不一定完全代表操作顺序,因为:
执行是并发的,但对stdout的写入是同步的
每个函数调用和通道发送/接收都为调度程序提供了切换的机会,因此即使使用进行运行
GOMAXPROCS=1
,它也可以在打印和通道操作(在读取器或写入器中)之间切换goroutines。
TL; DR:在记录并发操作时,不要过多地阅读日志消息的顺序。
- 1 回答
- 0 关注
- 247 浏览
添加回答
举报
0/150
提交
取消