Golang CSP
不要通过共享内存来通信,而应该通过通信来共享内存。
CSP模型用于描述两个独立的并发实体通过共享的通信管道(channel)进行通信的并发模型。Golang借用process和channel两个概念作为并发的理论支持。process在golang表现就是goroutine是实际并发执行的实体,每个实体之间通过channel通信实现数据共享。
channel初始化
使用channel必须make初始化。
unBufferChan := make(chan Type, 0) // Type: int、string...
bufferChan := make(chan Type, N) // 有缓存的通道
如果使用未初始化的channel会有dead lock错误:
func main() {
var x chan int
go func() {
x <- 1
}()
<-x
}
--------
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan receive (nil chan)]:
main.main()
单向channel
单向channel主要用在函数声明中。是约定,但是强制必须这样。
// 输入一个只能写的channel,返回一个只能读的channel
func foo(ch chan<- int) <-chan int {...}
// context包的Done()方法。
func (c *Context) Done() <-chan struct{} {
return nil
}
channel读写
ch := make(chan int, 10)
// 读操作
x <- ch
// 写操作
ch <- x
- 读
- 从空的缓冲channel里读消息,会block。
- 从无缓冲channel读消息,如果没有另一个goroutine正在写,会block。
- 从已关闭的channel读消息,==v,ok := <-c==,v为通道类型的默认值,ok为false。
- 写
- 向无缓冲channel写消息,如果没有另一个goroutine正在读,会block。
- 向已关闭的channel写消息,会panic。==panic: send on closed channel==。
select
select内channel有点特殊,不会block,与golang编译有关。
select {
case e, ok := <-ch1:
...
case e, ok := <-ch2:
...
default:
}
for {
select {
...
}
}
// 超时控制
select {
case <- ch:
// get data from ch
case <- time.After(2 * time.Second)
// read data from ch timeout
}
range
一旦 channel 关闭,channel 内部数据读完之后循环自动结束。
for x := range ch {
fmt.Println(x)
...
}
channel关闭
ch := make(chan int)
// 关闭
close(ch)
- 关
- 重复关闭channel,会panic。==panic: close of closed channel==。
参考
https://www.jianshu.com/p/36e246c6153d
http://legendtkl.com/2017/07/30/understanding-golang-channel/