热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

GO调度模型:GMP

一、GO调度器的由来二、GO的调度模型:可以抽象出三个实体:M(thread)、P(processor&#

一、GO"调度器"的由来


二、GO的调度模型

      可以抽象出三个实体:M(thread)、P(processor)、G(goroutine)

G:GO运行时对goroutine的描述,G中存放并发执行的代码入口地址、上下文、运行环境(关联的P和M)、运行栈等执行相关的信息。G的新建、休眠、恢复、停止都受到Go运行时的管理。

       GO运行时的监控线程会监控G的调度,G不会长久地阻塞系统线程,运行时的调度器会自动切换到其他G上运行。G新建或恢复时会添加到运行队列,等待M取出并运行。

M:OS内核线程,是操作系统层面调度和执行的实体。M仅负责执行,M不停地被唤醒或创建。然后执行。

P:代表M和G所需要的资源,是对资源的一种抽象管理,P不是一个段代码实体,而是一个管理的数据结构,P主要是降低M对G的复杂性,增加一个间接的控制层数据结构。P控制GO代码的并行度,它不是实体。

      P持有G的队列,P可以隔离调度,解除P和M的绑定就解除了M对一串G的调用。

G并不是执行体,而是存放并发执行体的元信息,包括并发执行的入口函数、堆栈、上下文等信息。G由于保存的是元信息,为了减少对象的分配和回收,G对象可以复用,只需要将相关元信息初始化为新值即可。

M仅负责执行,M启动时进入运行时的管理代码,这段管理代码必须拿到P后,才能执行调度。

P的数目默认是CPU核心的数量M和P的数目差不多,但运行时会根据当前的状态动态地创建M,M有一个最大值上限:10000G与P是M:N的关系,M可以成千上万,远远大于N.

GMP模型设计思想:


三、调度器的设计策略


四、Work Stealing算法的基本原理

    M和P构成一个运行时环境,每个P有一个本地的可调度的G队列,队列里面的G会被M依次调度执行,如果本地队列空了,则去全局队列偷取一部分G,如果全局队列也是空的,则去其他的P中偷取一部分G。


五、什么时候创建M、P、G?

程序启动过程中会初始化空闲P列表,P是这个时候创建的,同时第一个G也是在初始化过程中被创建的。

每个并发调用都会初始化一个新的G任务,如何唤醒M执行任务。这个唤醒不是特定唤醒某个线程去工作,而是先尝试获取当前线程M,如果无法获取,则从全局调度的空闲M列表获取可用的M,如果没有可用的M,则新建M,然后绑定P和GY运行。M和P不是一一对应的,而是按需分配的。

M线程管理调度切换堆栈的逻辑,但是M必须拿到P后才能运行,可用看到M是自驱动的,单需要P的配合。



六、goroutine经历的过程

Go协程阻塞太长时间会发生什么?
协程的切换时间片是10ms,也就是说 goroutine 最多执行10ms就会被 M 切换到下一个 G。这个过程,又被称为 中断,挂起。

Go协程遇到异步系统调用是怎么做的?
假设M的任务队列里有G1、G2,G1遇到异步系统调用时,M会先执行G2,G1异步返回时,插入回M的任务队列尾部。

Go协程遇到同步系统调用是怎么做的?
假设M的任务队列里有G1、G2,G1遇到同步系统调用时,G1会被调度到另外一个完全空闲的M上执行(如果不存在,则先创建一个新的M),G1同步返回时,插入回M的任务队列尾部。
 


推荐阅读
author-avatar
qyc_3830179
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有