英文:
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)
}
}
}()
我预期第一个goroutine在尝试将"test1"
写入通道时会被阻塞,直到第二个goroutine接收到数据。预期的输出应该是:
Sending test1...
Received: test1
Sending test2...
Received: test2
然而,当我实际运行这个示例时,输出结果却是:
Sending test1...
Sending test2...
Received: test1
Received: test2
从输出结果来看,发送操作似乎没有像预期的那样被阻塞。这是怎么回事呢?
英文:
Consider the following snippet of Go code:
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)
}
}
}()
<sub>Full source: http://play.golang.org/p/yY6JQzDMvn</sub>
I expect that the first goroutine will block when attempting to write "test1"
to the channel until the receive in the second goroutine. The expected output would be:
Sending test1...
Received: test1
Sending test2...
Received: test2
However, when I actually run the example, I end up with:
Sending test1...
Sending test2...
Received: test1
Received: test2
It would appear by the output that the send is not blocking as one would expect. What's going on here?
答案1
得分: 5
这是由两个goroutine中的竞争条件引起的。默认情况下,Go运行时使用单个线程来处理所有的goroutine,因此执行是串行的。考虑以下可能的代码执行情况:
- 第一个goroutine被
Sleep()
调用阻塞 - 第二个goroutine在通道上等待接收
- 第一个goroutine在
Sleep()
调用结束后恢复执行 "test1"
被写入通道,导致阻塞- 第二个goroutine接收到值,但在打印输出之前,执行切换回第一个goroutine
- 第一个goroutine打印
"Sending test2..."
并将第二个值写入通道,再次阻塞 - 第二个goroutine在被抢占的位置继续执行,并打印
"Received: test1"
消息 - 循环再次执行并接收第二个值
总结起来,发送操作确实是阻塞的,只是由于输出的顺序问题看起来不是这样。
英文:
This is caused by a race condition in the two goroutines. By default, the Go runtime uses a single thread for all goroutines, so execution is serialized. Consider the following possible scenario for executing the code above:
- the first goroutine is blocked by a
Sleep()
call - the second goroutine is blocked waiting for a receive on the channel
- the first goroutine resumes execution after the
Sleep()
call ends "test1"
is written to the channel, which blocks- the second goroutine receives the value but before printing the output, execution switches back to the first goroutine
- the first goroutine prints
"Sending test2..."
and writes the second value to the channel which again blocks - the second goroutine resumes where it was preempted and prints the
"Received: test1"
message - the loop is executed again and receives the second value
In summary, the send is indeed blocking, it just doesn't appear to be due to the order of output.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论