开发者学堂课程【Go 语言核心编程 - 面向对象、文件、单元测试、反射、TCP 编程:管道基本介绍】学习笔记,与课程紧密联系,让用户快速学习知识。
课程地址:https://developer.aliyun.com/learning/course/626/detail/9753
管道基本介绍
内容介绍
一、使用全局变量加锁同步改进程序
二、为什么需要 channel
三、channel 的介绍
一、使用全局变量加锁同步改进程序
1. 这里有一个间题需要给大家说明
//主线程休眠10秒,为的是让协程完成任务
//如果没有这句话,主线程很快就退出 m中还没有结果呢
time .sleep(10*time.Second)
lock.Lock()
for k,v:=range m {
fmt.Printf(“%d!=%v\n”,k,v)
}
lock.Unlock()
红字的部分为什么需要加互斥锁,按理说10秒数上面的协程都应该执行完,后面就不应该出现资源竞争的问题了,但是在实际运行中,还是可能在红框部分出现(运行时增加-race 参数,确实会发现有资源竞争问题),因为我们程序从设计上可以知道10秒就执行完所有协程,但是主线程并不知道,因此底层可能仍然出现资源争夺,因此加入互斥锁即可解决问题
2. Mutex 是一个互斥锁,可以创建为其他结构体的字段;零值为解锁状态。
Mutex 类型的锁和线程无关,可以由不同的线程加锁和解动。
二、为什么需要 channel
1. 前面使用全局变量加锁同步来解决 goroutine 的通讯,但不完美
2. 主线程在等待所有 goroutine 全部完成的时间很难确定,我们这里设置10秒,仅仅是估算。
3. 如果主线程休眠时间长了,会加长等待时间,如果等待时间短了,可能还有goroutine 处于工作状态,这时也会随主线程的退出而销毁
4. 通过全局变量加锁同步来实现通讯,也并不利用多个协程对全局变量的读写操作。
5. 上面种种分析都在呼唤一个新的通讯机制-channel
若不设置休眠时间,则得不到所有结果,若设置时间过长,也会出现相应的系列问题,即主线程的休眠时间不好估算,不好分析的复杂问题等等原因都呼唤着新通讯机制channel的到来。如果不设置时间,就不会有结果。编译后,结果不全。
编译结果如下:
//休眠10秒钟【第二个问题】
//time.sleep(time. second * 5)
//这里我们输出结果,变量这个结果
lock.Lock()
for i, v := range myMap {
fmt.Printf("map[%d]=%d\n", i, v)
}
lock.Unlock()
}
如果没有休眠时间,那么加锁就没有任何意义。
三、channel 的介绍
1. channle 本质就是一个数据结构-队列【示意图】
简单流程:
管道像对列一样排队,圆圈代表数据,管道本身具有大小、容量,当放入数据时,数据依次放在管道中。读取出时,也逐个取出,先取出第一个,同时长度减少,但容量不变。队列是一种数据结构。
2.数据是先进先出【FIFO : first in ,first out】
先放入的数据则先被取出,与then恰好相反
3. 线程安全,多 goroutine 访问时,不需要加锁,就是说 channel 本身就是线程安全的
编译器在底层维护,channel 本身的线程就是安全的,所以它不需要加锁
4. channel 是有类型的,一个 string 的 channel 只能存放 string 类型数据
int 类型就只可放入 int 类型,管道可以指定数据类型
5. 示意图:
Channel 是线程安全,多个协程操作同一个管道时候,不会发生资源竞争问题。
对示意图要有形象的认识。