GMP初探

G(Goroutine):协程,用户级的轻量级线程。

M:对内核线程的封装

P:为G和M的调度对象,主要用途是用来执行goroutine,维护了一个goroutine队列,即runqueue

由来

单进程时代

这个时代不需要调度器,早起的操作系统每个程序就是一个进程,直到一个程序运行完,才能进入下一个进程,一切的程序只能串行发生。

很容易出现的问题就是计算机只能一个一个的处理,而且如果某一进程在进行读写操作,进程阻塞会带来CPU时间的浪费。

多进程/线程时代

后来操作系统具有最早的并发能力:多进程并发,当一个进程阻塞的时候,切换到另外等待执行的进程,这样就能尽量把CPU利用起来。

进程虚拟内存会占用4GB[32位操作系统],而线程也要大约4MB。 大量的进程/线程出现新的问题:高内存占用,以及频繁调度带来的cpu损耗。

线程分为“内核态”线程和“用户态”线程,一个“用户态”线程必须要绑定一个“内核态”线程。

但是CPU对“用户态”线程是无感知的。 这样,就把用户态的“线程”叫为了协程。

这个时候,就发展为了多个协程绑定到一个线程上的模式。

N:1

N个协程绑定1个线程。 优点是协程的切换非常快速,缺点是一旦某协程阻塞,造成线程阻塞,本进程的其它协程都会法执行。

img
1:1

1个协程1个线程。

协程的调度由CPU完成。

M:N

克服了以上两种模型的缺点,实现起来也是最复杂的。

img

被废弃的goroutine调度器:GM

G表示Goroutine,M表示线程

M 想要执行、放回 G 都必须访问全局 G 队列,并且 M(线程) 有多个,即多线程访问同一资源需要加锁进行保证互斥 / 同步,所以全局 G 队列是有互斥锁进行保护的。

img

缺点:

  1. 创建、销毁、调度 G 都需要每个 M 获取锁。
  2. M之间的频繁切换增加系统开销

GMP是什么?

在GM的基础上引进了P(处理器)。

通过调度器来把可运行的goroutine分配到工作线程上。

  1. 全局队列(Global Queue):存放等待运行的 G。
  2. P 的本地队列:同全局队列类似,存放的也是等待运行的 G,存的数量有限,不超过 256 个。新建 G’时,G’优先加入到 P 的本地队列,如果队列满了,则会把本地队列中一半的 G 移动到全局队列。
  3. P 列表:所有的 P 都在程序启动时创建,并保存在数组中,最多有 GOMAXPROCS(可配置) 个。
  4. M:线程想运行任务就得获取 P,从 P 的本地队列获取 G,P 队列为空时,M 也会尝试从全局队列一批 G 放到 P 的本地队列,或从其他 P 的本地队列一半放到自己 P 的本地队列。M 运行 G,G 执行之后,M 会从 P 获取下一个 G,不断重复下去。

img

GMP设计策略

复用线程:避免频繁的创建、销毁线程,而是对线程的复用。
1)work stealing 机制
当本线程无可运行的 G 时,尝试从其他线程绑定的 P 偷取 G,而不是销毁线程。
2)hand off 机制
当本线程因为 G 进行系统调用阻塞时,线程释放绑定的 P,把 P 转移给其他空闲的线程执行。

抢占

goroutine最多占用CPU10ms,防止其它goroutine被饿死。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Jacob_云飞

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值