Goroutine 和 Channel 是 Go 语言并发编程的两大基石。Goroutine 用于执行并发任务,Channel 用于 goroutine 之间的同步、通讯。编程
在Golang的并发哲学里,有一句很是著名的话:安全
Do not communicate by sharing memory; instead, share memory by communicating.
意思是:不要经过共享内存来通讯,而要经过通讯来实现内存共享,它依赖CSP(Communication Sequence Process) 模型,简称通讯顺序进程。并发
Go提倡使用通讯的方法代替共享内存,当一个Goroutine须要和其余Goroutine资源共享时,Channel就会在他们之间架起一座桥梁,并提供确保安全同步的机制。工具
Channel本质上仍是一个队列,遵循FIFO(First In-First Out)原则,spa
建立通道须要用到关键字make,格式以下:3d
通道实例 := make(chan 数据类型)
通道建立后,就可使用通道进行发送和接收操做。code
通道的写入使用特殊的操做符<-,将数据经过通道发送的格式为:blog
通道变量 <- 值
(能够简单理解为箭头方向为传递的值最终去向)接口
// 建立一个空接口通道 ch := make(chan interface{}) // 将0放入通道中 ch <- 0 // 将hello字符串放入通道中 ch <- "hello"
通道的读取一样使用<-操做符,通道接收有以下特性:队列
通道的数据接收一共有如下 4 种写法:
1) 阻塞式接收
阻塞模式接收数据时,接收值只有一个,格式以下:
data := <-ch
执行该语句时程序将会阻塞,直到接收到数据并赋值给 data 变量。
2) 非阻塞接收数据
使用非阻塞方式从通道接收数据时,语句不会发生阻塞,格式以下:
data, ok := <-ch
data:表示接收到的数据。未接收到数据时,data 为通道类型的零值。
ok:表示是否接收到数据。
特色:非阻塞的通道接收方法可能形成高的 CPU 占用,不建议这么使用。
3) 忽略接收的数据
忽略从通道返回的任何数据,格式以下:
<-ch
特色:该方法也是阻塞的,必须等到通道返回了程序才会继续往下走。
4) 循环接收
通道的数据接收能够借用 for range 语句进行多个元素的接收操做,格式以下:
for data := range ch { // do sth. }
通道 ch 是能够进行遍历的,遍历的结果就是接收到的数据。数据类型就是通道的数据类型。经过 for 遍历得到的变量只有一个,即上面例子中的 data。
通常来讲,通道都是双向的,即数据能够进入和输出。可是,为了符合某些特殊业务场景,官方还提供了只支持读(Read Only)或只支持写(Write Only)的通道,格式以下:
//定义只读通道 ch_r := <-chan interface{} //定义只写通道 ch_w := <-chan interface{}
Go语言中有缓冲的通道(buffered channel)是一种在被接收前能存储一个或者多个值的通道。这种类型的通道并不强制要求 goroutine 之间必须同时完成发送和接收。通道会阻塞发送和接收动做的条件也会不一样。只有在通道中没有要接收的值时,接收动做才会阻塞。只有在通道没有可用缓冲区容纳被发送的值时,发送动做才会阻塞。
有缓冲通道的定义方式以下:
通道实例 := make(chan 通道类型, 缓冲大小)
下面我借用如下的图片来讲明下这个通道原理
Go语言中无缓冲的通道(unbuffered channel)是指在接收前没有能力保存任何值的通道。这种类型的通道要求发送 goroutine 和接收 goroutine 同时准备好,才能完成发送和接收操做。
无缓冲通道的定义方式以下:
通道实例 := make(chan 通道类型)
为了讲得更清楚一些,我也找了一张额外的图来讲明:
在第 1 步,两个 goroutine 都到达通道,但哪一个都没有开始执行发送或者接收。在第 2 步,左侧的 goroutine 将它的手伸进了通道,这模拟了向通道发送数据的行为。这时,这个 goroutine 会在通道中被锁住,直到交换完成。在第 3 步,右侧的 goroutine 将它的手放入通道,这模拟了从通道里接收数据。这个 goroutine 同样也会在通道中被锁住,直到交换完成。在第 4 步和第 5 步,进行交换,并最终在第 6 步,两个 goroutine 都将它们的手从通道里拿出来,这模拟了被锁住的 goroutine 获得释放。两个 goroutine 如今均可以去作别的事情了。
GoLang的通道是支撑并发系统稳定高效运行的重要工具,只有充分了解了它,才能在业务开发和问题排查中找到最关键的方案。知己知彼,百战不殆。