Go Channels 行为看起来不一致
Go Channels behaviour appears inconsistent
我发现无缓冲通道的工作方式不一致 - 这要么是 Go 中的不一致,要么是我对 Go 的理解...
这是一个带有输出的简单示例。 'inconsistency' 与 'make channel' 行。
package main
import (
"fmt"
)
func send(sendto chan string) {
fmt.Println("send 1")
sendto <- "Hello"
fmt.Println("send 2")
sendto <- "World"
fmt.Println("send 3")
sendto <- ""
fmt.Println("send() exit")
}
func main() {
//hole := make(chan string)
//hole := make(chan string, 0)
hole := make(chan string, 1)
go send(hole)
fmt.Println("main loop")
carryon := true
for carryon {
msg := <- hole
if msg == "" {
carryon = false
} else {
fmt.Println(" recd ", msg)
}
}
}
当我如上所述 运行 时,输出符合预期(对于缓冲区大小为 2 的情况也符合预期)。即通道有一个缓冲区 1,它保存一个值 - 在下一次尝试写入时,有一个上下文切换到 main 以允许它使用第一个值。
main loop
send 1
send 2
recd Hello
send 3
recd World
send() exit
当我将 make 通道行更改为:
hole := make(chan string, 0)
输出为:
main loop
send 1
send 2
recd Hello
recd World
send 3
send() exit
我原以为 send 2
和 recd Hello
会相反...
我得到与 hole := make(chan string)
相同的输出
我查看了规格,上面写着
The capacity, in number of elements, sets the size of the buffer in the channel. If the capacity is zero or absent, the channel is unbuffered and communication succeeds only when both a sender and receiver are ready. Otherwise, the channel is buffered and communication succeeds without blocking if the buffer is not full (sends) or not empty (receives).
谁能解释一下
- 为什么我的期望是错误的 - 请善待
- 或者 Go 是否真的错了
谢谢
大致:发送和接收同时发生。详细信息在确定此行为的 Go 内存模型中进行了解释。并发代码复杂...
communication succeeds only when both a sender and receiver are ready
关键是这不需要接收方立即开始处理它收到的消息。特别是在您的情况下,它已准备就绪,因此它无需调用调度程序即可接收值(无上下文切换)。 goroutine 继续 运行 直到它再次尝试发送,此时接收器还没有准备好,因此调用调度程序等
这两个 goroutine 的时间轴显示了正在发生的事情:
send() main()
fmt.Println("send 1")
sendto <- "Hello" msg := <- hole // sender and receiver both ready
fmt.Println("send 2")
fmt.Println(" recd ", msg) // msg is "Hello"
sendto <- "World" msg := <- hole // sender and receiver both ready
fmt.Println(" recd ", msg) // msg is "World"
fmt.Println("send 3")
sendto <- ""
fmt.Println("send() exit")
send 2
在 recd Hello
之前打印,因为 send() 运行s 在 运行 时间安排 main() 到 运行 之前打印语句再次。
打印这两条消息没有happens before关系。它们可以按任一顺序打印。
我发现无缓冲通道的工作方式不一致 - 这要么是 Go 中的不一致,要么是我对 Go 的理解...
这是一个带有输出的简单示例。 'inconsistency' 与 'make channel' 行。
package main
import (
"fmt"
)
func send(sendto chan string) {
fmt.Println("send 1")
sendto <- "Hello"
fmt.Println("send 2")
sendto <- "World"
fmt.Println("send 3")
sendto <- ""
fmt.Println("send() exit")
}
func main() {
//hole := make(chan string)
//hole := make(chan string, 0)
hole := make(chan string, 1)
go send(hole)
fmt.Println("main loop")
carryon := true
for carryon {
msg := <- hole
if msg == "" {
carryon = false
} else {
fmt.Println(" recd ", msg)
}
}
}
当我如上所述 运行 时,输出符合预期(对于缓冲区大小为 2 的情况也符合预期)。即通道有一个缓冲区 1,它保存一个值 - 在下一次尝试写入时,有一个上下文切换到 main 以允许它使用第一个值。
main loop
send 1
send 2
recd Hello
send 3
recd World
send() exit
当我将 make 通道行更改为:
hole := make(chan string, 0)
输出为:
main loop
send 1
send 2
recd Hello
recd World
send 3
send() exit
我原以为 send 2
和 recd Hello
会相反...
我得到与 hole := make(chan string)
我查看了规格,上面写着
The capacity, in number of elements, sets the size of the buffer in the channel. If the capacity is zero or absent, the channel is unbuffered and communication succeeds only when both a sender and receiver are ready. Otherwise, the channel is buffered and communication succeeds without blocking if the buffer is not full (sends) or not empty (receives).
谁能解释一下
- 为什么我的期望是错误的 - 请善待
- 或者 Go 是否真的错了
谢谢
大致:发送和接收同时发生。详细信息在确定此行为的 Go 内存模型中进行了解释。并发代码复杂...
communication succeeds only when both a sender and receiver are ready
关键是这不需要接收方立即开始处理它收到的消息。特别是在您的情况下,它已准备就绪,因此它无需调用调度程序即可接收值(无上下文切换)。 goroutine 继续 运行 直到它再次尝试发送,此时接收器还没有准备好,因此调用调度程序等
这两个 goroutine 的时间轴显示了正在发生的事情:
send() main()
fmt.Println("send 1")
sendto <- "Hello" msg := <- hole // sender and receiver both ready
fmt.Println("send 2")
fmt.Println(" recd ", msg) // msg is "Hello"
sendto <- "World" msg := <- hole // sender and receiver both ready
fmt.Println(" recd ", msg) // msg is "World"
fmt.Println("send 3")
sendto <- ""
fmt.Println("send() exit")
send 2
在 recd Hello
之前打印,因为 send() 运行s 在 运行 时间安排 main() 到 运行 之前打印语句再次。
打印这两条消息没有happens before关系。它们可以按任一顺序打印。