如下代码,运行时会造成死锁
func main() {
var t = make(chan int)
go func() {
for i := 1;i<=10;i++ {
t <- i
}
}()
for t1 := range t{
fmt.Println(t1)
}
fmt.Println("ok")
}
原因是:for range是阻塞式读取channel,只有channel close之后才会结束,否则会一直读取,通道里没有值了,还继续读取就会阻塞,程序就会报死锁。
改成如下即可:
func main() {
var t = make(chan int)
go func() {
for i := 1;i<=100;i++ {
t <- i
}
close(t)
}()
for t1 := range t{
fmt.Println(t1)
}
fmt.Println("ok")
}
有时会没有输出,原因是主协程已经退出了,此时我们只要加个sleep即可
golang中的channel思路就是生产者消费者,无论生产者写入数据还是消费者读取数据都是阻塞的,理解这个的思路要基于阻塞这个前提。
fori这种形式是自己判断从channel中读取多少次
for range 这种就是是runtime帮我们来判断了,他的判断标准是 close(ch)
你的fori改成多一次循环同样会被go判定为 deadlock
因为最后一次的读取会一直阻塞在那里,原因是生产者不再生产了,消费者还阻塞在那里等待。go判断到这个会一直阻塞在这里的场景就直接抛出错误退出了,否则这个进程就一直hang在这里还不易被发现。
导致这种错误的情况有两种
生产者
没有消费者消费channel中的数据,channel中的数据已经填充满了,但是还在往里写入,此刻是要阻塞等待的,由于没有消费者,这个阻塞会一直阻塞下去
消费者
生产者不再生产数据了,也就是是 channel 中会一直为空了,但是消费者还在读取channel中的数据,这个读取也是阻塞等待的,channel中不会再有数据,这个等待也是会一直等待下去
参考:go通道channel使用for-range造成死锁,而使用for计数器迭代却不会? - SegmentFault 思否