我刚接触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号,甚至没有将其放入通道中。为什么会这样?
答案 0 :(得分:5)
不是。您的Println("PUT into channel")
发生在 之后,将其放在通道上,这意味着在执行该打印语句之前,有机会从通道中读取它。
示例输出中的实际执行顺序如下:
2
写入通道。2
。goroutine: GET 2
。PUT into channel 2
您对频道的读写操作按预期的顺序进行,只是您的打印语句使它看起来不正常。
如果您将作者的操作顺序更改为:
fmt.Println("PUT into channel", j)
ch <- j
您可能会看到输出更接近您的期望。但是,它不一定完全代表操作顺序,因为:
GOMAXPROCS=1
运行,它也可以在打印和通道操作(在读取器或写入器中)之间切换goroutine。 TL; DR:在记录并发操作时,不要对日志消息的顺序读太多。