Golang 缓冲通道在发送之前接收数据
Golang buffered channel receive data before even sent
我对 golang 很陌生。今天在测试通道在 Golang 中的工作方式时,我感到非常困惑。
根据教程:
Sends to a buffered channel block only when the buffer is full. Receives block when the buffer is empty.
我的测试程序是这样的:
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")
发生在 之后 你把它放在频道上,这意味着它有机会在执行打印语句之前从频道中读取它。
示例输出中的实际执行顺序大致如下:
- Writer 例程将
2
写入通道。
- Reader 例程从通道接收
2
。
- Reader 例程打印
goroutine: GET 2
.
- Writer 例程打印
PUT into channel 2
您的读写 from/to 频道正在按预期顺序进行,只是您的打印语句让它看起来乱序了。
如果您将作者的操作顺序更改为:
fmt.Println("PUT into channel", j)
ch <- j
您可能会看到更接近您预期的输出。但是,它仍然不一定完全代表操作顺序,因为:
- 并发执行,但写入 stdout 是同步的
- 每次函数调用和通道send/receive都是调度器切换的机会,所以即使运行
GOMAXPROCS=1
,它也可以在打印和通道操作之间切换goroutines(在reader 或作者)。
TL;DR:记录并发操作时,不要过多地阅读日志消息的顺序。
我对 golang 很陌生。今天在测试通道在 Golang 中的工作方式时,我感到非常困惑。
根据教程:
Sends to a buffered channel block only when the buffer is full. Receives block when the buffer is empty.
我的测试程序是这样的:
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")
发生在 之后 你把它放在频道上,这意味着它有机会在执行打印语句之前从频道中读取它。
示例输出中的实际执行顺序大致如下:
- Writer 例程将
2
写入通道。 - Reader 例程从通道接收
2
。 - Reader 例程打印
goroutine: GET 2
. - Writer 例程打印
PUT into channel 2
您的读写 from/to 频道正在按预期顺序进行,只是您的打印语句让它看起来乱序了。
如果您将作者的操作顺序更改为:
fmt.Println("PUT into channel", j)
ch <- j
您可能会看到更接近您预期的输出。但是,它仍然不一定完全代表操作顺序,因为:
- 并发执行,但写入 stdout 是同步的
- 每次函数调用和通道send/receive都是调度器切换的机会,所以即使运行
GOMAXPROCS=1
,它也可以在打印和通道操作之间切换goroutines(在reader 或作者)。
TL;DR:记录并发操作时,不要过多地阅读日志消息的顺序。