其他分享
首页 > 其他分享> > GMP模型

GMP模型

作者:互联网

Golang协程调度器原理 & GMP设计思想

地址:https://www.bilibili.com/video/BV19r4y1w7Nx

1.Golang调度器的由来

1.1 早期单进程操作系统

所有进程只能顺序执行,产生问题:

1.2 多进程/多线程操作系统

​ 以时间片轮询的机制并发执行程序 (并行与CPU核数有关),很显然多线程/多进程可以解决1.1中进程阻塞导致CPU浪费的问题(即是你程序阻塞,时间片到了,也会强制释放CPU)。产生问题:

1.3 协程

​ 为了解决1.2的CPU高消耗和内存高占用问题,而内核态无法修改,所以尝试修改用户态。将线程分为用户线程和内核线程。而内核线程称为线程,用户线程称为协程,由于CPU视野只有内存空间,因此协程的开辟对CPU来说是无感的

​ 线程通过协程调度器绑定多个协程,而CPU视野只有内核空间,所以对CPU而言只有单一线程即进程,因此此方法可有效解决CPU高消耗的问题

​ 每个语言对协程进行不同处理。Golang对协程进行相应优化:对协程co-routine重命名为goroutine;修改协程内存大小,每个goroutine只有几KB大小,因此可以大量创建;可灵活调度,切换成本较低。所以最后重点就落到了优化协程调度器上面。

2.协程调度器和GMP模型设计思想

2.1 早期协程调度器

​ 各个线程首先需要去全局G队列拿锁,才能去执行协程挂载的任务,此时该线程不释放锁就导致其他线程无法去执行协程上的任务。

缺点:

2.2 GMP模型简介

G ------ goroutine协程
P ------ 协程调度器
M ------ 线程

​ 每个 P 保存了当前执行的协程G内部资源信息(堆栈地址和变量参数等),所以M要先去获取P才能去执行G。创建的G会优先存放在本地队列,如果本地队列满了(最多256个G),会存放至全局G队列。

P 的个数,可由环境变量中$GOMAXPROCS设置;或在程序中可通过runtime.GOMAXPROCS()设置。

2.3 调度器设计策略

2.3.1 复用线程

复用线程可避免创建与销毁线程中进行的资源消耗;

实现的两种机制:

2.3.2 利用并行

​ 可充分发挥多核优势,通过设置GOMAXPROCS设置协程调度器的个数,通常并不会挂满,设置为CPU核数/2。

2.3.3 抢占

​ 相较于老的调度器而言,老调度器中只有当当前协程释放CPU,另一个协程才去执行;现在调度器以时间片而言,一个时间片到了后会强制释放CPU给其他协程使用。

2.3.4 全局G队列

​ 当线程空闲时,会首先从其他线程对应协程本地队列偷取(即work stealing机制),如果偷不到,会从全局G队列进行获取(前提要先去获取锁)。

2.4 "go func()"的历程

开始:

如执行go func()代码产生阻塞现象:

为了节省资源,提高CPU利用率

2.5 调度器的生命周期

`

2.6 可视化的GMP编程

地址:https://www.bilibili.com/video/BV19r4y1w7Nx?p=7&spm_id_from=pageDriver

标签:执行,协程,队列,模型,调度,线程,GMP,CPU
来源: https://www.cnblogs.com/wustjq/p/16439702.html