Go原理:调度器和GPM模型 您所在的位置:网站首页 复合材料专业考研分数线 Go原理:调度器和GPM模型

Go原理:调度器和GPM模型

2023-04-01 06:54| 来源: 网络整理| 查看: 265

前言#

我们都知道 Goroutine 是 Go 的语言特色,也可以称之为协程。协程是运行在线程上的,而不同的协程和线程之间的调度则受“调度器”这一机制控制。

那么什么是调度器,它又是如何实现的呢?

调度器#

我们追根溯源,了解一下调度器是如何出现的。

早期单进程操作系统根本不需要调度器,进程遵循顺序执行,每个进程都要等上一个进程执行完才能执行。可是这样一个进程阻塞,后面的进程也无法执行。后来有了多进程/多线程操作系统,一个进程阻塞可以让 CPU 执行别的进程,这就有了调度需求(Linux 中进程和线程等价控制)。但是进程间切换需要占用 CPU 资源,并且线程也占用较大内存(4MB)。因为对于 CPU 来说只管理线程的调度即“内核态”,对每个线程绑定的用户空间或是说具体运行代码是什么样的并不关心,因此可以将这部分用户空间划分出来用户自己控制,就叫做协程,而“内核态”的线程也就是受 CPU 控制的那部分还叫做线程。

如果一个协程绑定一个线程,那协程的创建、删除和切换都是由 CPU 完成,代价太高;如果多个协程绑定一个线程,一旦某个协程阻塞,线程也会阻塞,其他协程也运行不了了。

因此使用多个协程绑定多个线程的模式,那协程的分配和线程的选择就需要中间有一个调度器的存在。

GMP 模型#

调度器是一个组件,也是一种机制的实现。Go 语言的调度器是一个 GMP 模型。所谓 GMP 模型就是协程 G (Goroutine),线程 M (thread) 以及处理器 P (Processor)。

你可能感到很疑惑,不是说协程和线程的事吗,怎么又冒出来个处理器。其实早期 Go 的调度器是没有处理器的,只有多个协程和一个全局 Goroutine 队列。但是这样就涉及到 Goroutine 的竞争,效率并不高。所以后来引入了处理器 P,以及它带着的本地 Goroutine 队列。

因此在 GMP 模型中,有一个装载 G 的全局队列,每个 P 还有一个装载 G 的本地队列。

我们打个比方,协程 G 就像是游戏里的任务,而线程 M 就是想做任务的玩家,而处理器 P 是各地任务大厅的 NPC。

M 需要做任务就要先找到一个 P 绑定,从它的本地队列接任务 G 做,做完之后再接。

听上去很简单,也还有一些细节需要补充:

P 是程序是程序启动时创建的,由环境变量控制数量;M 绑定的 P 中如果没有 G 了,会从全局队列中找 G,没有的话会从其他 P 的本地队列偷一半 G 过来;如果本地队列满了,再创建或执行完回来的 G 会放到全局队列;如果 M 阻塞了,会将它的 P 分给一个休眠队列的 M 或是新增一个 M;程序开始时会先创建一个线程 M0,负责初始化和启动第一个 G,第一个 G 一般就是 main 函数;每个 M 创建时会创建一个属于自己的 G0,负责调度,包括其他协程的切换等。参考#

[Go三关-典藏版] Golang调度器GPM原理与调度全分析 Go 语言设计与实现 6.5 调度器



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有