channel
在goroutine并发执行的时候,需要在函数和函数之间进行通信。Go语言并发模式CSP(communicating Sequents Processes),通过通信共享内存。
Go 语言中的通道(channel)是一种特殊的类型。通道像一个传送带或者队列,总是遵循先入先出(First In First Out)的规则,保证收发数据的顺序。
goroutine
是go
语言并发的执行体,channel
是它们之间的通道channel
是将一个goroutine
发送到另一个goroutine
的通信机制
channel类型
channel是一种类型,是一种引用类型,需要make
进行初始化才能够使用,空值是nil
,关键字是chan
。
1 | var 变量名 chan 元素类型 |
初始化
**通道是一种类型。**声明通道之后必须进行初始化, 缓冲大小是可选的。Go
语言中需要进行初始化的类型
- 切片
slice
- 映射
map
- 通道
channel
1 | make (chan 元素类型, [缓冲大小]) |
channel 操作
三种操作
发送和接收使用<-
符号
- 发送send
- 接收receive
- 关闭close
1 | ch <- 10 // 将10发送到通道中 |
关于通道的关闭:
- 只有接收方
goroutine
所有的数据都发送完毕后才会关闭 - 通道是种类型,是可以被垃圾回收机制回收的;通道的关闭不是必须的
- 对一个关闭的通道再发送值就会导致
panic
- 对一个关闭的通道进行接收会一直获取值直到通道为空。
- 对一个关闭的并且没有值的通道执行接收操作,会得到对应类型的零值。
- 关闭一个已经关闭的通道会导致panic。
demo
1 | package main |
单向通道
1 | package main |
channel异常总结
channel | nil | 非空(有值) | 空 | 满 | 未满 |
---|---|---|---|---|---|
接收 | 阻塞 | 接收值 | 阻塞 | 接收值 | 接收值 |
发送 | 阻塞 | 发送值 | 发送值 | 阻塞 | 发送值 |
关闭 | panic | 关闭成功,读完数据返回零值 | 关闭成功,返回零值 | 关闭成功,读完数据返回零值 | 关闭成功,读完数据返回零值 |
关闭已经关闭的channel
会引起panic
work pool机制(goroutine池)
1 | package main |
select 多路复用
同时从多个通道中接收数据,可以通过for遍历来实现,但是运行性能差,Go内置select关键字来实现。类似switch语句
- 有多个case分支和一个默认分支
- 每个case对应一个通道(接收或者发送),select等待某个case的通信操作完成,执行该语句
1 | for { |
1 | // demo1 |
资源竞争问题
下面的栗子:表示多个协程同时向map
空间中写入数据,没有对全局便量加锁,造成了资源竞争的问题concurrent map writes?
确定是否存在资源竞争问题:在编译程序的时候,加上
-race
参数go build -race main.go
1 | package main |
解决1
全局加锁:全局变量进行加入互斥锁。当某个协程在进程操作的时候,其他的协程排队等待。执行完毕,解锁,下个协程开始执行。使用
sync
包
1 | package main |