Channel创建方式:
var c1 chan [value type]
c1 = make([channel type] [value type], [capacity])
[value type] 定义的是 Channel 中所传输数据的类型。
[channel type] 定义的是 Channel 的类型,其类型有以下三种:
"chan" 可读可写 : chan int 则表示可读写 int 数据的 channel
"chan<-" 仅可写 : chan<- float64 则表示仅可写64位 float 数据的 channel
"<-chan" 仅可读 : <-chan int 则表示仅可读 int 数据的 channel
[capacity] 是一个可选参数,其定义的是 channel 中的缓存区 (buffer)。
如果不填则默认该 channel 没有缓冲区 (unbuffered)。
对于没有缓冲区的 channel,消息的发送和收取必须能同时完成,否则会造成阻塞并提示死锁错误。
Channel死锁:对 channel 的发送和接收动作永远不会同时发生,从而阻塞造成死锁。
fatal error: all goroutines are asleep - deadlock!
避免死锁方式1:使用goroutine并发执行。
通过 go 语句定义发送操作的方程在另一个协程并发运行,chan读取没有数据时会阻塞等待,从而能够解决死锁
避免死锁方式2:使用 buffer。
为 channel 添加一个缓冲区(buffer),这样只要 buffer 没有用尽,阻塞就不会发生,死锁也不会发生。
Example:chan.go
同样的,在 select 控制结构中,如果两个 channel 都阻塞且没有 default 流程分支时,也将产生死锁(deadlock)。
Example:select.go
不同于传统的多线程通过共享内存来通信,CSP讲究的是“以通信的方式来共享内存。
普通的线程并发模型,就是像Java、C++、或者Python,他们线程间通信都是通过共享内存的方式来进行的。
非常典型的方式就是,在访问共享数据(例如数组、Map、或者某个结构体或对象)的时候,通过锁来访问,因此,在很多时候,衍生出一种方便操作的数据结构,叫做“线程安全的数据结构”。
例如Java提供的包”java.util.concurrent”中的数据结构。Go中也实现了传统的线程并发模型。
Go的CSP并发模型,是通过 goroutine 和 channel 来实现的。