package mainimport ( "fmt")func write(ch chan int) { for i := 0; i < 5; i++ { fmt.Println("avaliable", i) ch <- i fmt.Println("successfully wrote", i, "to ch") } close(ch)}func main() { ch := make(chan int) go write(ch) for v := range ch { fmt.Println("read value", v, "from ch") }}输出avaliable 0successfully wrote 0 to chavaliable 1read value 0 from chread value 1 from chsuccessfully wrote 1 to chavaliable 2successfully wrote 2 to chavaliable 3read value 2 from chread value 3 from chsuccessfully wrote 3 to chavaliable 4successfully wrote 4 to chread value 4 from ch由于这是一个无缓冲的通道,它应该在数据写入它时立即阻塞,直到另一个 goroutine 从同一通道读取。但它接受的数据超出了它的能力。预期行为package mainimport ( "fmt" "time")func write(ch chan int) { for i := 0; i < 5; i++ { fmt.Println("avaliable", i) ch <- i fmt.Println("successfully wrote", i, "to ch") } close(ch)}func main() { ch := make(chan int) go write(ch) time.Sleep(time.Second) for v := range ch { fmt.Println("read value", v, "from ch") time.Sleep(time.Second) }}输出avaliable 0read value 0 from chsuccessfully wrote 0 to chavaliable 1read value 1 from chsuccessfully wrote 1 to chavaliable 2read value 2 from chsuccessfully wrote 2 to chavaliable 3read value 3 from chsuccessfully wrote 3 to chavaliable 4read value 4 from chsuccessfully wrote 4 to ch如果在整个代码中放置了一些计时器,以便主 goroutine 在每次迭代之前被阻塞,它就会按预期工作。
2 回答

HUX布斯
TA贡献1876条经验 获得超6个赞
您无法从输出中推断出任何内容,因为“读取值”和“成功写入”Printfs 执行之间没有顺序保证。(在通道发送之前发生的“可用”Printf 和在相应通道接收之后发生的“读取值”Printf 之间存在一个,您可以看到输出中永远不会违反该顺序)。
通道没有缓冲任何东西,因为它没有缓冲;只是通道发送完成后,两个不同的 goroutine 以不确定的顺序运行。有时发送方先走并打印“成功写入”消息,有时接收方先走并打印“读取值”消息。没有一个“领先”超过一个值,因为它们仍然在通道发送上完全同步;他们只是在比赛之后立即打印他们的状态消息。
当您将 Sleep 调用添加到 main 时,它恰好使运行的 goroutinewrite
在等待发送下一个值时总是被阻塞,而正在运行的 goroutinemain
在调用时阻塞Sleep
。当定时器超时时,主协程被唤醒,并立即发现它在通道上等待它的东西,抓住它,然后重新进入睡眠状态,然后write
协程被唤醒。通过放慢速度,您已经让调度程序以一致的顺序运行事物(尽管这仍然部分是运气问题);没有睡眠,一切都尽可能快地运行,结果显然是随机的。
- 2 回答
- 0 关注
- 229 浏览
添加回答
举报
0/150
提交
取消