时刻提醒自己必须深入理解channel的特性,有自己的思考,而不是死记硬背。之后可以阅读熟悉下channel的底层实现原理。
向无缓冲的channel发送/接收数据
无缓冲的channel必须有接收才能发送,下述代码在执行的时候会引发deadlock错误
1 | func main() { |
解决方法是启用一个goroutine去接收值,如下:
1 | func recv(c chan int) { |
思考:下述情况会引发死锁吗?
1 | func main() { |
答案是不会引发死锁,虽然子协程一直阻塞在传值语句,但是和主协程之间并无产生联系,当主协程退出的时候子协程也就跟着退出了。
延伸:如果主协程和子协程之间建立了联系会产生死锁吗?
1 | func main() { |
输出有缓冲的channel中所有的值
当读取完channel中的数据后,继续读取的操作会造成阻塞,且阻塞发生在主协程中,故会引发阻塞。
1 | func main() { |
解决方法是发送完所有数据后则关闭channel,或者通过select方法中的default进行处理,如下:
1 | func main() { |
过度向有缓冲的channel写入数据
写入数据超过channel的容量的时候,也会引发死锁。
1 | func main() { |
解决方法是通过select方法中的default进行处理:
1 | func main() { |
总结
上述提到的死锁,是指在程序的主协程中发生的情况,如果上述情况是发生在非主协程中,读取或者写入的情况是发生阻塞的,而不是死锁(此时需要考虑是否需要主动关闭子协程)。实际上,阻塞情况省去了我们加锁的步骤,反而是更加有利于代码编写,要合理的运用阻塞。