Create 14.2.md

This commit is contained in:
glight2000
2015-12-25 13:34:53 +08:00
parent 50d4d88cc0
commit 87184288ee

61
eBook/14.2.md Normal file
View File

@@ -0,0 +1,61 @@
# 14.2 协程间的信道
## 14.2.1 概念
在第一个例子中,协程是独立执行的,他们之间没有通信。他们必须通信才会变得更有用:彼此之间发送和接收信息并且协调/同步他们的工作。协程可以使用共享变量来通信,但是很不提倡这样做,因为这种方式给所有的共享内存的多线程都带来了困难。
而Go有一个特殊的类型`通道channel`,像是通道(管道),可以通过它们发送类型化的数据在协程之间通信,可以避开所有内存共享导致的坑;通道的通信方式保证了同步性。数据通过通道:同一时间只有一个协程可以访问数据:所以不会出现数据竞争,设计如此。数据的归属(可以读写数据的能力)被传递。
工厂的传送带是个很有用的例子。一个机器(生产者协程)在传送带上放置物品,另外一个机器(消费者协程)拿到物品并打包。
通道服务于通信的两个目的:值的交换,同步的,保证了两个计算(协程)任何时候都是可知状态。
![](../images/14.2_fig14.1.png?raw=true)
通常使用这样的格式来声明通道:`var identifier chan datatype`
未初始化的通道的值是nil。
所以通道稚嫩传输一种类型的数据,比如`chan int`或者`chan string`,所有的类型都可以用于通道,空接口`interface{}`也可以。甚至可以(有时非常有用)创建通道的通道。
通道实际上是类型化消息的队列使数据得以传输。它是先进先出FIFO结构的所以可以保证发送给他们的元素的顺序有些人知道通道可以比作Unix shells中的双向管道tw-way pipe。通道也是引用类型所以我们使用`make()`函数来给它分配内存。这里先声明了一个字符串通道ch1然后创建了它实例化
```go
var ch1 chan string
ch1 = make(chan string)
```
当然可以更短: `ch1 := make(chan string)`
这里我们构建一个int通道的通道 `chanOfChans := make(chan chan int)`
或者函数通道: `funcChan := chan func()`(相关示例请看章节[14.17](14.17.md)
所以通道是对象的第一类型:可以存储在变量中,作为函数的参数传递,从函数返回以及通过通道发送它们自身。另外它们是类型化的,允许类型检查,比如尝试使用整数通道发送一个指针。
## 14.2.2 通信操作符 <-
这个操作符直观的标示了数据的传输:信息按照箭头的方向流动。
流向通道(发送)
`ch <- int1`表示用通道ch发送变量int1二进制操作符中缀 = 发送)
从通道流出(接收),三种方式:
`int2 = <- ch`表示变量int2从通道ch一元运算的前缀操作符前缀 = 接收接收数据获取新值假设int2已经声明过了如果没有的话可以写成`int2 := <- ch`
`<- ch`可以单独调用获取通道的(下一个)值,当前值会被丢弃,但是可以用来验证,所以以下代码是合法的:
```go
if <- ch != 1000{
...
}
```
## 链接
- [目录](directory.md)
- 上一节:[并发,并行和协程](14.1.md)
- 下一节:[协程同步:关闭通道-测试阻塞的通道](14.3.md)