goroutine-基本介绍
1.进程和线程介绍
程序、进程和线程的关系示意图
2.并发和并行
1) 多线程程序在单核上运行,就是并发
2) 多线程程序在多核上运行,就是并行
3) 示意图
小结
3.Go 协程和 Go 主线程
Go 主线程(有程序员直接称为线程/也可以理解成进程): 一个 Go 线程上,可以起多个协程,你可以 这样理解,协程是轻量级的线程。
Go 协程的特点
1) 有独立的栈空间
2) 共享程序堆空间
3) 调度由用户控制
4) 协程是轻量级的线程
主线程和协程执行流程图
小结
1) 主线程是一个物理线程,直接作用在 cpu 上的。是重量级的,非常耗费 cpu 资源。
2) 协程从主线程开启的,是轻量级的线程,是逻辑态。对资源消耗相对小。
3) Golang 的协程机制是重要的特点,可以轻松的开启上万个协程。其它编程语言的并发机制是一 般基于线程的,开启过多的线程,资源耗费大,这里就突显 Golang 在并发上的优势了。
4.MPG 模式基本介绍
5.管道 channel
不同 goroutine 之间如何通讯(解决资源争夺问题concurrent map writes)
1) 全局变量的互斥锁
2) 使用管道 channel 来解决
为什么需要 channel
1) 前面使用全局变量加锁同步来解决 goroutine 的通讯,但不完美。
2) 主线程在等待所有 goroutine 全部完成的时间很难确定,仅仅是估算。
3) 如果主线程休眠时间长了,会加长等待时间,如果等待时间短了,可能还有 goroutine 处于工作 状态,这时也会随主线程的退出而销毁 。
4) 通过全局变量加锁同步来实现通讯,也并不利用多个协程对全局变量的读写操作。
5) 上面种种分析都在呼唤一个新的通讯机制-channel。
channel 的基本介绍
1) channle 本质就是一个数据结构-队列。
2) 数据是先进先出【FIFO : first in first out】
3) 线程安全,多 goroutine 访问时,不需要加锁,就是说 channel 本身就是线程安全的。
4) channel 有类型的,一个 string 的 channel 只能存放 string 类型数据。
5) 示意图
定义/声明 channel
举例:
说明:
1.channel 是引用类型
2.channel 必须初始化才能写入数据, 即 make 后才能使用
3.管道是有类型的,intChan 只能写入 整数
channel 使用的注意事项
1) channel 中只能存放指定的数据类型
2) channle 的数据放满后,就不能再放入了
3) 如果从 channel 取出数据后,可以继续放入 4
) 在没有使用协程的情况下,如果 channel 数据取完了,再取,就会报 dead lock
练习
代码
package main import ( "fmt" "math/rand" ) type person struct { Name string Age int Address string } func main() { var perchan = make(chan person, 10) for i := 0; i < 10; i++ { x := person{ Name: string(rand.Intn(100)), Age: rand.Int(), Address: string(rand.Intn(100)), } perchan <- x } for { v := <-perchan fmt.Println(v) if len(perchan) == 0 { break } } }
channel 的关闭
使用内置函数 close 可以关闭 channel, 当 channel 关闭后,就不能再向 channel 写数据了,但是仍然 可以从该 channel。
channel 的遍历
channel 支持 for--range 的方式进行遍历,请注意两个细节
1) 在遍历时,如果 channel 没有关闭,则回出现 deadlock 的错误。
2) 在遍历时,如果 channel 已经关闭,则会正常遍历数据,遍历完后,就会退出遍历。