为什么不阻塞此通道上的发送?
Why aren't sends on this channel blocking?
考虑以下 Go 代码片段:
c := make(chan string)
go func() {
time.Sleep(100 * time.Millisecond)
fmt.Println("Sending test1...")
c <- "test1"
fmt.Println("Sending test2...")
c <- "test2"
fmt.Println("Done sending")
}()
go func() {
for {
select {
case n := <-c:
fmt.Println("Received:", n)
}
}
}()
完整来源: http://play.golang.org/p/yY6JQzDMvn
我希望第一个 goroutine 在尝试将 "test1"
写入通道时会阻塞,直到第二个 goroutine 接收为止。预期输出为:
Sending test1...
Received: test1
Sending test2...
Received: test2
然而,当我实际 运行 这个例子时,我最终得到:
Sending test1...
Sending test2...
Received: test1
Received: test2
输出显示发送没有像预期的那样阻塞。这是怎么回事?
这是由两个 goroutine 中的竞争条件引起的。默认情况下,Go 运行时对所有 goroutine 使用单个线程,因此执行是序列化的。考虑以下执行上述代码的可能场景:
- 第一个 goroutine 被
Sleep()
调用阻塞
- 第二个 goroutine 被阻塞等待通道上的接收
- 第一个goroutine在
Sleep()
调用结束后继续执行
"test1"
写入通道,阻塞
- 第二个 goroutine 接收值 但在打印输出之前,执行切换回第一个 goroutine
- 第一个 goroutine 打印
"Sending test2..."
并将第二个值写入再次阻塞的通道
- 第二个 goroutine 在它被抢占的地方恢复并打印
"Received: test1"
消息
- 循环再次执行并接收到第二个值
综上所述,send确实是阻塞的,只是看起来不是输出顺序的问题。
考虑以下 Go 代码片段:
c := make(chan string)
go func() {
time.Sleep(100 * time.Millisecond)
fmt.Println("Sending test1...")
c <- "test1"
fmt.Println("Sending test2...")
c <- "test2"
fmt.Println("Done sending")
}()
go func() {
for {
select {
case n := <-c:
fmt.Println("Received:", n)
}
}
}()
完整来源: http://play.golang.org/p/yY6JQzDMvn
我希望第一个 goroutine 在尝试将 "test1"
写入通道时会阻塞,直到第二个 goroutine 接收为止。预期输出为:
Sending test1...
Received: test1
Sending test2...
Received: test2
然而,当我实际 运行 这个例子时,我最终得到:
Sending test1...
Sending test2...
Received: test1
Received: test2
输出显示发送没有像预期的那样阻塞。这是怎么回事?
这是由两个 goroutine 中的竞争条件引起的。默认情况下,Go 运行时对所有 goroutine 使用单个线程,因此执行是序列化的。考虑以下执行上述代码的可能场景:
- 第一个 goroutine 被
Sleep()
调用阻塞 - 第二个 goroutine 被阻塞等待通道上的接收
- 第一个goroutine在
Sleep()
调用结束后继续执行 "test1"
写入通道,阻塞- 第二个 goroutine 接收值 但在打印输出之前,执行切换回第一个 goroutine
- 第一个 goroutine 打印
"Sending test2..."
并将第二个值写入再次阻塞的通道 - 第二个 goroutine 在它被抢占的地方恢复并打印
"Received: test1"
消息 - 循环再次执行并接收到第二个值
综上所述,send确实是阻塞的,只是看起来不是输出顺序的问题。