-
goroutine 看一个需要
- 需要:要求统计 1 – 90000000000 的数字中,那些是素数?
-
剖析思路:
- 传统的办法,就是应用一个循环,循环的判断各个数是不是素数「效率很低」
- 应用并发或者并行的形式,将统计素数的任务分配个多个 goroutine 去实现,这时就会应用到 goroutine「速度进步很多」
- goroutine 根本介绍
过程和线程介绍
-
- 过程就是程序程序在操作系统中的一次执行过程,是零碎进行资源分配和调度的根本单元
- 线程是过程的一个执行实例,是程序执行的最小单元,它是比过程更小的能独立运行的根本单元
- 一个过程能够创立和销毁多个线程,同一个过程中的多个线程能够并发执行
- 一个程序至多有一个过程,一个过程至多有一个线程
-
并发和并行
- 多线程程序在单核上运行,就是并发
- 多线程程序在多核上运行,就是并行
-
小结
- 并发:因为是在一个 cpu 上,比方有 10 个线程,每个线程执行 10ms(进行轮询操作),从人的角度看,如同这 10 个线程都在运行,然而从宏观上看,
在某个工夫点看,其实只有一个线程在执行,这就是并发。
- 并行:因为是在多个 cpu 上 (比方有 10 个 cpu),比方有 10 个线程,每个线程执行 10ms(各自在不同的 cpu 上执行),从人的角度看,这 10 个线程都在运行,然而从宏观上看,在某个工夫点看,也同时有 10 个线程在执行,这就是并行
-
go 协程和 go 主线程
- go 主线程 (有程序员间接称为线程 / 也能够了解程过程) : 一个 go 线程上,能够起多个协程,你能够这里了解,协程是轻量级的线程「编译器做优化」
-
go 协程的特点
- 有独立的栈空间
- 共享程序堆空间
- 调度由用户管制
- 协程是轻量级的线程
-
channel (管道)- 看个需要
- 需要:当初要计算 1 -200 的各个数的阶乘,并且把各个数的阶乘放入到 map 中,最初显示进去,要求应用 goroutine 实现
剖析思路
- 应用 goroutine 来实现,效率高,然而会呈现并发 / 并行平安问题
- 这里就提出了不同的 goroutine 如何通信的问题
代码实现
- 应用 goroutine 来实现 (看看应用 goroutine 并发实现会呈现什么问题? 而后咱们去解决)
- 在运行某个程序时,如何晓得是否存在资源竞争问题,办法很简略,在编译程序时。减少一个参数。-race 即可
-
代码实现见 goroutine 和 channel/goroutine_channel.go
下面的案例就呈现了资源的竞争的问题
-
不同 goroutine 之间如何通信
- 全局变量的互斥锁
- 应用管道 channel 来解决
-
应用全局变量加锁同步改良程序
- 因为没有对全局变量 m 加锁,因而会呈现资源抢夺问题,代码会呈现谬误,提醒 fatal error: concurrent map writes
- 解决方案: 退出互斥锁
- 咱们的数的阶乘很大,后果会越界,能够将求阶乘改成 sum+=uint64(i)
- 改良代码实现见 goroutine 和 channel/goroutine_channel_new.go
-
为什么须要 channel
- 后面应用全局变量加锁同步来解决 goroutine 的通信,但不完满
- 主线程在期待所有 goroutine 全副实现的工夫很难确定,咱们这里设置 10s, 仅仅是估算
- 如果主线程休眠工夫长了,会加长等待时间,如果工夫短了,可能还有 goroutine 处于工作状态,这时也会随主线程的退出而销毁
- 同步全局变量加锁同步来通信,也不利用多个协程对全局变量的读写操作
- 下面种种剖析都在召唤一个新的通信机制 - channel
-
channel 的根本介绍
- channel 实质就是一个数据结构 - 队列
- 数据是先进先出(FIFO:first in first out)
- 线程平安,多 goroutine 拜访时,不须要加锁,就是说 channel 自身就是线程平安的
- channel 有类型的,一个 string 的 channel 只能寄存 string 类型数据
- 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
- 管道的初始化,写入数据到管道,从管道读取数据以及根本注意事项
-
- 代码实现见 goroutine 和 channel/channel.go
-
channel 应用的注意事项
- channel 中只能寄存指定的数据类型
- channel 的数据放满后,就不能再放入了
- 如果从 channel 取出数据后,能够持续放入
- 在没有应用协程的状况下,如果 channel 数据取完了,在取,就会报 dead lock
-
读写 channel 案例演示
- 案例见 goroutine 和 channel/intChan.go
….. 具体见上面连贯
细说 goroutine 和 channel