channel基本概念及使用
- 为什么需要 channel
- 1) 前面使用全局变量加锁同步来解决 goroutine 的通讯,但不完美
- 2) 主线程在等待所有 goroutine 全部完成的时间很难确定,这里设置 10 秒,仅仅是估算。
- 3) 如果主线程休眠时间长了,会加长等待时间,如果等待时间短了,可能还有 goroutine 处于工作状态,这时也会随主线程的退出而销毁
- 4) 通过全局变量加锁同步来实现通讯,也并不利用多个协程对全局变量的读写操作。
- 5) 上面种种分析都在呼唤一个新的通讯机制-channel
- channel 的基本介绍
- 1) channle 本质就是一个数据结构-队列
- 2) 数据是先进先出【FIFO : first in first out】
- 3) 线程安全,多 goroutine 访问时,不需要加锁,就是说 channel 本身就是线程安全的
- 4) channel 有类型的,一个 string 的 channel 只能存放 string 类型数据。
- 5) 示意图:
channel基本使用
定义/声明 channel
- var 变量名 chan 数据类型
- 举例:
- var intChan chan int (intChan 用于存放 int 数据)
- var mapChan chan map[int]string (mapChan 用于存放 map[int]string 类型)
- var perChan chan Person
- var perChan2 chan *Person
- ...
- 说明
- channel 是引用类型
- channel 必须初始化才能写入数据, 即 make 后才能使用
- 管道是有类型的,intChan 只能写入 整数 int
- 创建管道并make
//1. 创建一个可以存放3个int类型的管道 var intChan chan int intChan = make(chan int, 3) //2. 看看intChan是什么 fmt.Printf("intChan 的值=%v intChan本身的地址=%p\n", intChan, &intChan)
- 输出结果:
intChan 的值=0xc000104080 intChan本身的地址=0xc000006028
- 向管道写入数据,注意点, 当我们给管写入数据时,不能超过其容量
intChan<- 10 num := 211 intChan<- num intChan<- 50
- 查看管道长度和容量
//查看管道的长度和cap(容量) fmt.Printf("channel len= %v cap=%v \n", len(intChan), cap(intChan)) // 3, 3
- 从管道中读取数据
var num2 int num2 = <-intChan fmt.Println("num2=", num2) fmt.Printf("channel len= %v cap=%v \n", len(intChan), cap(intChan)) // 2, 3
- 输出结果:
num2= 211 channel len= 2 cap=3
- 在没有使用协程的情况下,如果我们的管道数据已经全部取出,再取就会报告 deadlock
num3 := <-intChan num4 := <-intChan num5 := <-intChan
- 输出结果:
fatal error: all goroutines are asleep - deadlock! goroutine 1 [chan receive]: