channel的简介
Go语言的并发模型实CSP(Communicating Sequential Processes)提倡通过通信共享内存而不是通过共享内存实现通信。
虽然可以使用共享内存进行数据交换,但是共享内存在不同的goroutine中容易发生竞态问题。为了保证数据交换的正确性,必须使用互斥量对内存进行加锁,这种做法势必造成性能问题。
channel
:就是Go语言中,将一个goroutine发送特定值到另一个goroutine的通信机制。
Go 语言中的通道(channel)是一种特殊的类型。通道就是一个队列,总是遵循先入先出(First In First Out)的规则,保证收发数据的顺序。每一个通道都是一个具体类型的导管,也就是声明channel的时候需要为其指定元素类型。
channel的使用
channel的类型
- channel是一种引用类型,声明通道的格式如下:
var 变量 chan 元素类型
-------------------------
var ch1 chan int // 声明一个传递整型的通道
var ch2 chan bool // 声明一个传递布尔型的通道
var ch3 chan []int // 声明一个传递int切片的通道
创建channel
由于通道是引用类型,通道的值默认为nil
var ch1 chan int
fmt.Println(ch1)//<nil>
声明通道后需要使用make函数初始化才能使用。
make初始化通道的语法为:
make(chan 元素类型, [缓冲大小])
操作channel
channel有三种操作:发送,接收,关闭
其中发送和接收都是使用的:<-
ch1 := make(chan int)
ch1 <- 10//将10发送到ch1中
x :=<-ch1 //从ch1接收值并赋给x
关闭:
close(ch1)
注意:关闭通道并不是必须的,只有在通知接收方goroutine所有的数据都发送完毕的时候才需要关闭通道,通道可以被垃圾回收。
对一个已经关闭的通道进行发送值或者是关闭操作会导致panic。
对一个关闭的通道进行接收值可以一直取到值,直到通道为空,当通道都没有值了,再取值取得的只能是对应类型的零值。
无缓冲通道
无缓冲通道又称作阻塞通道:
ch1 := make(chan int)
ch1 <- 10//将10发送到ch1中
通过ch1 := make(chan int)
创建的就是无缓冲通道,无缓冲通道只有接收方存在时才能发送值,否则就将出现死锁错误。
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan send]:
main.main()
有两种解决方法:
- 启动一个goroutine去接收
func recvdata(c chan int) {
data :=<-c
fmt.Println("接收成功data",data)
}
func main() {
//var ch1 chan int
//fmt.Println(ch1)
ch1 := make(chan int)
go recvdata(ch1)//启动goroutine接收通道里面的值
ch1<-10//发送10
fmt.Println("发送成功")
}
同步通道
:无缓冲通道上的发送操作会阻塞,直到另一个goroutine在该通道上执行接收操作,这时值才能发送成功,两个goroutine将继续执行。相反,如果接收操作先执行,接收方的goroutine将阻塞,直到另一个goroutine在该通道上发送一个值。
使用无缓冲通道进行通信将导致发送和接收的goroutine同步化。因此,无缓冲通道也被称为同步通道。
有缓冲通道
有缓冲通道也是解决无缓冲通道存在问题的解决方案
只要通道的容量大于零,那么该通道就是有缓冲的通道,通道的容量表示通道中能存放元素的数量。
创建有缓冲通道:
ch := make(chan int, 1) // 创建一个容量为1的有缓冲区通道
这样也不会出现deadlock情况。而这个数据也就存在于这个通道,进行缓冲。
单向通道
Go语言中提供了单向通道,限制数据只能发送或者接收
1.chan<- int是一个只能发送的通道,可以发送但是不能接收;
out chan <-int
2.<-chan int是一个只能接收的通道,可以接收但是不能发送。
in <-chan int
双向通道可以转变为单向,但是单向通道却不能变为双向。