## 为什么需要管道
1. 主线程在等待所有goroutine全部完成的时间很难确定,比如设置10秒仅仅是估算
2. 如果主线程休眠时间长了,会加长等待时间;如果等待时间短了,可能还有goroutine处于工作状态,这时也会随主线程的退出而小灰
3. 通过全局变量加锁来实现通讯,也并不利用多个协程对全局变量的读写操作
## 管道介绍
1. channel本质是一个数据结果-队列
2. 数据是先进先出
3. 线程安全,多goroutine访问时,不需要加锁,就是说channel本身就是线程安全的
4. channel是有类型的,一个string的channel只能存放string类型数据
## 管道基本使用
```
var 变量名 chan 数据类型
var intChan chan int
var mapChan chan map[int]string
var perChan chan Person
var perChan1 chan *Person
```
1. channel是引用类型
2. channel必须初始化才能写入数据,即make后才能使用
3. 管道是有类型的,只能写入对应类型的数据
## 管道读写特性
1. 默认是可读可写
2. 声明为只写 `var chan2 chan<- int`
3. 声明为只读 `var chan3 <chan int`
4. 应用场景,函数内防止误操作
## 示例代码
```
package main
import (
"fmt"
)
func main() {
var intChan chan int
intChan = make(chan int, 3) //容量为3 int类型
fmt.Printf("incChan的值=%v\\n", intChan) //地址
//向channel写入数据,写入的数据量不能超过管道的容量(cap)
intChan <- 10
num := 211
intChan <- num
fmt.Printf("channel len=%v cap=%v\\n", len(intChan), cap(intChan)) //len=2 cap=3
//从管道中读取数据
num2 := <-intChan
fmt.Printf("num2=%v channel len=%v cap=%v\\n", num2, len(intChan), cap(intChan)) //len=1 cap=3
//在没有使用协程的情况下,如果管道数据已经全部取出,再取会报告deadlock
num3 := <-intChan
num4 := <-intChan
fmt.Printf("num3=%v num4=%v", num3, num4)
}
```
![](https://img.kancloud.cn/a7/d3/a7d39340bfd77e4bc843094f6b579c54_397x165.png)
## interface chan
取出的时候需要类型断言,否则可以打印输出,但是无法获取内部的元素
## 关闭管道
使用内置函数`close`,关闭后无法写入数据,但能读取数据
## 遍历管道
for-range,不能使用普通的for
```
for v := range intChan2{ //没有下标index
}
```
1. 在遍历时,如果channel没有关闭,则会出现deadlock错误
2. 在遍历时,如果channel已经关闭,则会正常遍历数据,遍历完后,退出遍历
- 数据类型
- 数组array
- 切片slice
- 字符串string
- map
- 结构体struct
- 方法func
- 匿名结构体(继承)
- 字段别名
- 接口interface
- 常量
- 基础语法
- 循环for
- 遍历
- 函数func
- defer
- 异常处理error
- 访问范围
- 包
- 类型断言
- 文件
- 打开文件
- 读取文件
- 写文件
- 判断是否存在
- 拷贝文件
- JSON
- 序列化
- 反序列化
- 命令行
- 杂项
- Windows下配置加速
- 相关链接
- 占位符
- 随机数rand
- 单元测试
- goroutine
- 并发和并行
- 协程和主线程
- MPG模式
- 设置CPU数量
- 全局互斥锁
- 管道
- 示例1
- 示例2
- select
- 异常捕获
- 反射
- 示例
- 示例-改变值
- 网络编程
- TCP编程
- 示例一
- redis