在看本篇文章前我们需要了解阻塞的概念
- 在执行过程中暂停,以等待某个条件的触发 ,我们就称之为阻塞
在Go中我们make一个channel有两种方式,分别是有缓冲的和没缓冲的
- 缓冲
channel
即buffer channel
创建方式为make(chan TYPE,SIZE)
- 如
make(chan int,3)
就是创建一个int
类型,缓冲大小为3
的channel
- 如
- 非缓冲
channel
即unbuffer channel
创建方式为make(chan TYPE)
- 如
make(chan int)
就是创建一个int
类型的非缓冲channel
- 如
- 非缓冲
channel
和 缓冲channel
的区别- 非缓冲
channel
,channel
发送和接收动作是同时发生的 - 例如
ch := make(chan int)
,如果没goroutine
读取接收者<-ch
,那么发送者ch<-
就会一直阻塞 - 缓冲
channel
类似一个队列,只有队列满了才可能发送阻塞
- 非缓冲
-
代码演示
-
非缓冲
channel
package main
import (
"fmt"
"time"
)
func loop(ch chan int) {
for {
select {
case i := <-ch:
fmt.Println("this value of unbuffer channel", i)
}
}
}
func main() {
ch := make(chan int)
ch <- 1
go loop(ch)
time.Sleep(1 * time.Millisecond)
}
- 这里会报错
fatal error: all goroutines are asleep - deadlock!
就是因为ch<-1
发送了,但是同时没有接收者,所以就发生了阻塞 - 但如果我们把
ch <- 1
放到go loop(ch)
下面,程序就会正常运行
- 缓冲
channel
的阻塞只会发生在channel
的缓冲使用完的情况下
package main
import (
"fmt"
"time"
)
func loop(ch chan int) {
for {
select {
case i := <-ch:
fmt.Println("this value of unbuffer channel", i)
}
}
}
func main() {
ch := make(chan int,3)
ch <- 1
ch <- 2
ch <- 3
ch <- 4
go loop(ch)
time.Sleep(1 * time.Millisecond)
}
- 这里也会报
fatal error: all goroutines are asleep - deadlock!
,这是因为channel
的大小为3
,而我们要往里面塞4
个数据,所以就会阻塞住 - 解决的办法有两个
- 把
channel
开大一点,这是最简单的方法,也是最暴力的 - 把
channel
的信息发送者ch <- 1
这些代码移动到go loop(ch)
下面 ,让channel
实时消费就不会导致阻塞了
- 把