关于go的channel阻塞问题
在看go入门指南时遇到一个问题,下面的程序为什么会产生死锁。
package main
import (
"fmt"
)
func f1(in chan int) {
fmt.Println(<-in)
}
func main() {
out := make(chan int)
out <- 2
go f1(out)
}
书中说到:
通道的发送/接收操作在对方准备好之前是阻塞的:
,按理说,out <- 2
等到fmt.Println(<-in)
准备好就可以执行了,不应该产生死锁啊,求解
但是,当我调整了一下顺序,就可以了
func f1(in chan int) {
fmt.Println(<-in)
}
func main() {
out := make(chan int)
go f1(out)
out <- 2
}
// 结果:
2
然后在调整一点
func f1(in chan int) {
in <- 2
fmt.Println("in")
}
func main() {
out := make(chan int)
<-out
go f1(out)
}
// 结果依然是死锁
如果此时和上面一样调整一下顺序
func f1(in chan int) {
in <- 2
fmt.Println("in")
}
func main() {
out := make(chan int)
go f1(out)
<-out
}
// 结果为 in
我又尝试了一下
func f1(in chan int) {
in <- 2
fmt.Println("in")
}
func main() {
out := make(chan int)
<-out
fmt.Println("out")
go f1(out)
}
此时的结果是死锁,还有一个关键的点是:没有打印出
out
我猜:是不是由于在执行<-out
时阻塞,而此时只有一个协程,并没有执行go f1(out)
,所以导致channel的双方并没有准备好,进而产生了死锁。不知道对不对,好纠结???
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
https://segmentfault.com/q/10...
完全一样的问题……
有啥好纠结的……
记住一点,单纯的out<-和<-in都会阻塞,只有两个同时进行了,才能继续执行。
这里你看上去有个协程,来执行<-in,但是实际上已经阻塞在out<-2了,协程没办法执行下去……
解决办法就两个,要么在out <- 2之前开一个协程去消费这个channel,
要么就给这个channel加个大小,让他里面默认能存1个数据,这样才不会阻塞,即:
make(chan int, 1)
Channel communication
Channel communication is the main method of synchronization between goroutines. Each send on a particular channel is matched to a corresponding receive from that channel, usually in a different goroutine.
A send on a channel happens before the corresponding receive from that channel completes.
This program:
var c = make(chan int, 10)
var a string
func f() {
}
func main() {
}
is guaranteed to print "hello, world". The write to a happens before the send on c, which happens before the corresponding receive on c completes, which happens before the print.
The closing of a channel happens before a receive that returns a zero value because the channel is closed.
In the previous example, replacing c <- 0 with close(c) yields a program with the same guaranteed behavior.
A receive from an unbuffered channel happens before the send on that channel completes.
This program (as above, but with the send and receive statements swapped and using an unbuffered channel):
var c = make(chan int)
var a string
func f() {
}
func main() {
}
is also guaranteed to print "hello, world". The write to a happens before the receive on c, which happens before the corresponding send on c completes, which happens before the print.
If the channel were buffered (e.g., c = make(chan int, 1)) then the program would not be guaranteed to print "hello, world". (It might print the empty string, crash, or do something else.)
The kth receive on a channel with capacity C happens before the k+Cth send from that channel completes.
This rule generalizes the previous rule to buffered channels. It allows a counting semaphore to be modeled by a buffered channel: the number of items in the channel corresponds to the number of active uses, the capacity of the channel corresponds to the maximum number of simultaneous uses, sending an item acquires the semaphore, and receiving an item releases the semaphore. This is a common idiom for limiting concurrency.
This program starts a goroutine for every entry in the work list, but the goroutines coordinate using the limit channel to ensure that at most three are running work functions at a time.
var limit = make(chan int, 3)
func main() {
}