如果我定义了一个没有缓冲区的通道,并将一个数据写入其中,它是立即阻塞(这样内核将寻找另一个未阻塞的goroutine,从该通道读取数据),还是继续执行,并在下一次某些代码再次尝试写入通道时阻塞(当它还没有被读取时)?
下面是我用来研究这个问题的两段代码。
code1:
package main
import "fmt"
func main() {
c := make(chan int)
go func() {
for i := 0;i < 3; i++ {
c <- i
fmt.Printf("number %v inserted into channel\n", i)
}
}()
for i := 0; i < 3; i++ {
fmt.Printf("number poped from channel %v\n", <-c)
}
}
输出如下所示:
number 0 inserted into channel
number poped from channel 0
number poped from channel 1
number 1 inserted into channel
number 2 inserted into channel
number poped from channel 2
在第一次写入c之后,这个goroutine似乎会继续执行,因为"number 0 inserted into channel“已经打印出来了。
code2:
package main
import "fmt"
func main() {
c := make(chan int)
c <- 2
fmt.Println("Something is written into channel")
<-c
}
这段代码无法正确运行,因为在运行时会报告死锁错误。
fatal error: all goroutines are asleep - deadlock!
在我看来,当c <-2被执行时,goroutine被阻塞(如果它没有被阻塞,fmt.Println行将被执行,继续执行将在<-c处解锁c)。当这个goroutine被阻塞时,内核会搜索其他goroutine,但是没有找到,所以它会报告一个死锁错误。
总而言之,在第一段代码中,我得出结论,写入通道不会立即阻塞goroutine,但从第二段代码开始会阻塞goroutine。我哪里搞错了,什么时候通道阻塞了goroutine?
发布于 2019-06-21 15:40:30
发送到没有可用缓冲区空间的通道会阻止发送方,直到发送可以完成;从没有可用消息的通道接收会阻止接收方,直到接收可以完成。未缓冲的通道永远不会有缓冲空间--在接收到数据之前发送数据块,反之亦然。这在Go之旅中有所介绍:https://tour.golang.org/concurrency/2
请记住,您的代码是并发的,因此您不能从输出语句的顺序中读取太多内容。在发送/接收操作之间以及将消息打印到stdout时,可以将goroutine置于睡眠状态。
https://stackoverflow.com/questions/56706566
复制