Loading [MathJax]/jax/input/TeX/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >golang 重要知识:golang 调度

golang 重要知识:golang 调度

原创
作者头像
lincoln
修改于 2021-07-30 02:27:54
修改于 2021-07-30 02:27:54
1.2K0
举报
文章被收录于专栏:后端后端

摘要

Go 的调度机制相当于我们微服务里的基础组件。很多运行时操作都涉及到了调度的关联。本文会细聊调度概念,策略,以及它的机制。当然,也少不了最常提及的 GMP 模型。

一、调度是什么?

计算机的资源有限的,像 CPU,内存都是固定的。但是同一时间可能会有多个任务要去完成,比如操作系统的定时监控,用户程序的运行等。

怎么让资源最大化的完成任务,这是调度需要考虑的关键点。

调度可以理解为一个指挥员,指导我们的程序按照一定的规则去获取资源,然后去执行里面的指令。

调度分配
调度分配

那么,一般的规则有哪些呢?

常见的调度策略有 2 种,一种是协作式调度,会让程序顺利的完成自己的任务,再把资源腾出来给其他程序使用。

另一种是抢占式调度,也就是让程序按一定的时间去占有这些资源,时间到了就被迫让出现有资源,给其他的程序轮流使用。

协作式调度有利于程序专注的完成自己的任务,但也可能会造成其他程序一直饿死,得不到执行。

协作式调度
协作式调度

抢占式调度有利于程序在资源的利用上雨露均沾,但是在不断的切换过程中,将会使得程序原本 10 ms 能完成的事,不得不延迟多几 ms。

抢占式调度
抢占式调度

注:Linux 操作系统也是采用了抢占式调度,并且使用了 CFS:完全公平调度算法。通过对程序大致的运行时间来平衡调度,让越没有执行过的程序,越快被调度到。

当前大多数操作系统都是采用抢占式调度来执行程序的,毕竟很多操作系统都是面向用户,需要很高的响应速度,而且只要切换程序的周期够短,例如 50ms,那对于用户来讲,就像没切换一样。

二、golang 的调度

上面提及到抢占式调度会有个频繁切换的过程,在切换时,需要不断的保存或恢复上下文信息。

而这会涉及到操作系统内核态和用户态的切换,性能损耗会很大。

对此,golang 实现了属于自己的调度模型,采用了基于协作的抢占式调度。之所以是"协作"的,是因为 Go 的调度时机是由用户自己设置的,而这里的用户指的是 golang 的运行时 runtime

它会在下面的事件发生时进行调度触发:

使用关键字 go 垃圾回收 系统调用,如访问硬盘 同步阻塞调用,如 使用 mutex、channel

如果上面什么事件都没发生,则会有 sysmon 来监控 goroutine 的运行情况,对长时间运行的 goroutine 进行标记。一旦 goroutine 被标记了,那么它就会下次发生函数调用时,将自己挂起,再触发调度。

这里需要说明下的是,runtime 它相当于 Java虚拟机,负责了 Go 的很多东西,例如调度垃圾回收、内存管理等,可以说是涵盖了 Go 的基础引擎了。

更重要的是 runtime 是运行在用户态上的,相当于 Go 的调度是在用户态这一层进行的。

这样,每当 Go 有调度产生时,就不会伴随着用户态和内核态的切换,而是像前面提到过的策略那样去触发调度,这就降低了并发时的内核态与用户态的切换成本了。

三、golang 的 GPM 模型

为了实现 golang 的调度,golang 抽象出了三个结构,也就是我们常见的 G、P、M

G:也就是协程 goroutine,由 Go runtime 管理。我们可以认为它是用户级别的线程。

goroutine 非常的轻量,初始分配只有 2KB,当栈空间不够用时,会自动扩容。同时,自身存储了执行 stack 信息、goroutine 状态以及 goroutine 的任务函数等。

P:processor 处理器。P 的数量默认跟 CPU 的核心数一样,如果是多核的 CPU,则会有多个 P 会被创建。

每当有 goroutine 要创建时,会被添加到 P 上的 goroutine 本地队列上,如果 P 的本地队列已满,则会维护到全局队列里。

在进行调度时,会优先从本地队列获取 goroutine 来执行。

如果本地队列没有,会从其他的 P 上偷取 goroutine。

如果其他 P 上也没有,则会从全局队列上获取 goroutine。

这样通过上面的策略,就能尽最大努力保证有 goroutine 可运行

M:系统线程。在 M 上有调度函数,它是真正的调度执行者,M 需要跟 P 绑定,并且会让 P 按上面的原则挑出个 goroutine 来执行。

M 虽然从 P 上挑选了 G 执行,但 M 并不保存 G 的上下文信息,而是 G 自己保存了相关信息,这样有利于转移到其他 M 上,在不同的 M 上运行。

GPM模型
GPM模型

GPM 模型的优势点在于 G 包含了执行任务相关信息,M 提供了执行环境,并且有调度机制。而 P 则是他们两者的粘合剂。

假如没有 P 。那么 M 就会有争夺 G 的竞争问题,并且 M 的数量会不可控,会出现过多的 M 去处理 G。

一旦超过了 CPU 的核心数,那么就会将性能耗费在上下文切换过程中。

有了 P 这一层后,M 优先从 P 的本地队列获取 goroutine,减少并发竞争。并且保证了最多跟 CPU 核心数一样的 goroutine 数量在并行运行,充分利用了多核优势,又不被滥用。

总结

相信看过本文后,各位对 Golang 的调度有了一定的了解。正是因为基于协作的抢占式调度和 GMP 模型,Golang 的高并发高性能才有了底层保障。当然,大伙也可以深入到源码去分析这些调度机制,这样离大神就更近一步了 ㋡...


感兴趣的朋友可以搜一搜公众号「 阅新技术 」,关注更多的推送文章。

可以的话,就顺便点个赞、留个言、分享下,感谢各位支持!

阅新技术,阅读更多的新知识。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
字节一面:go的协程比线程轻量,体现在哪?
01 用户态和内核态 Linux整个体系分为用户态和内核态(或者叫用户空间和内核空间), 那内核态究竟是什么呢? 本质上我们所说的内核态, 它是一种特殊的软件程序,特殊在哪?统筹计算机的硬件资源,例如
有态度的马甲
2022/03/30
1.7K0
字节一面:go的协程比线程轻量,体现在哪?
Golang 语言的 goroutine 调度器模型 GPM
Golang 语言与其他编程语言之间比较,最大的亮点就是 goroutine,使 Golang 语言天生支持并发,可以高效使用 CPU 的多个核心,而并发执行需要一个调度器来协调。
frank.
2021/01/22
1.4K0
Go语言高阶:调度器系列(1)起源
如果把语言比喻为武侠小说中的武功,如果只是会用,也就是达到四五层,如果用的熟练也就六七层,如果能见招拆招也得八九层,如果你出神入化,立于不败之地十层。
大彬
2019/04/11
8000
Go语言高阶:调度器系列(1)起源
从进程开始了解GMP模型
进程是操作系统分配资源(CPU、内存、文件)、调度任务和执行的一个基本单位。它拥有独立的内存空间、已分配的资源和独立的执行上下文。 线程是CPU调度的基本单位,同一进程内的线程共享了进程的资源和内存空间。
leobhao
2024/04/01
2240
从进程开始了解GMP模型
【深度知识】GO语言的goroutine并发原理和调度机制
Go语言最大的特色就是从语言层面支持并发(Goroutine),Goroutine是Go中最基本的执行单元。事实上每一个Go程序至少有一个Goroutine:主Goroutine。当程序启动时,它会自动创建。
辉哥
2019/08/05
1.8K0
【深度知识】GO语言的goroutine并发原理和调度机制
Golang(三)Goroutine原理
前言 最近用到了一些 Golang 异步编程的地方,感觉 Golang 相对于其他语言(如 Java)对多线程编程的支持非常大,使用起来也非常方便。于是决定了解一下 Goroutine 的底层原理。 Goroutine 本质是协程,是实现并行计算的核心。只需要在对应的函数前加上 Go 关键词即可异步执行: go func() { }() 基本概念 并发:一段时间内执行多个程序,即在一个 cpu 上切换着执行多项任务,宏观上是同时的,微观上是顺序执行 并行:同时执行多个程序,即在多个 cpu 上同时运行不同任
西凉风雷
2022/11/23
5660
Golang(三)Goroutine原理
从Golang调度器的作者视角探究其设计之道!
导语 | Golang核心开发人员、goroutine调度的设计者Dmitry Vyukov,在2019年的一个talk里深入浅出地阐述了goroutine调度的设计思想以及一些优化的细节。本文是笔者结合自身经验和认知的一点观后感,采用从零开始层层递进的方法,总结剖析了其背后的软件设计思想,希望对读者更好地理解goroutine调度GMP模型会有所帮助。 前言 视频地址: https://2019.hydraconf.com/2019/talks/7336ginp0kke7n4yxxjvld/ 这个视频我
腾讯云开发者
2022/03/18
3980
深入浅出Go调度器中的GMP模型
今天给大家介绍一下Go协程调度器的G-M-P的模型,以及一个线程在该模型下是如何被调度的。
Go学堂
2023/08/28
1.3K0
深入浅出Go调度器中的GMP模型
我所理解的 Go 的 GPM 模型
Go 语言(Golang)的一大显著特性是在其语法层面就内建了对协程,即 goroutine 的支持,并且其运行时(runtime)系统为这一功能提供了强大且原生的支撑。在我看来,选择使用协程而非传统的线程来支持高并发任务,带来了诸多益处:
Piper破壳
2025/05/25
1180
我所理解的 Go 的 GPM 模型
上周并发题的解题思路以及介绍Go语言调度器
今天的文章我首先说一下上篇文章里的思考题的解决思路,我会给出完整可运行的代码。之后通过观察程序的运行结果里的现象简单介绍Go语言的调度器是如何对goroutine进行调度的。
KevinYan
2020/06/09
5260
上周并发题的解题思路以及介绍Go语言调度器
golang调度机制
Golang的核心之一gorountine go语言非常重要的一个特性就是gorountine,有了这个东东,就可以很简单的做并发处理程序,比起c++和java的方式来说可以说简单了很多很多。那么go
黑光技术
2019/03/06
2.3K0
golang调度机制
Golang GMP模型
早期操作系统是单进程的,只能顺序执行进程,如果进程需要IO,必须要等IO结束才能继续运行,造成了严重的CPU资源的浪费。
月梦@剑心
2023/08/31
4890
Golang GMP模型
Go的任务调度单元与并发编程
本文主要介绍Go语言、进程、线程、协程的出现背景原因以及Go 语言如何解决协程的问题和并发编程的实现,本文的阅读时长约在15-20分钟左右,请合理的分配您的阅读时间。
葡萄城控件
2023/10/16
4000
Go的任务调度单元与并发编程
Go 运行时面试题
在 Go 语言中,goroutine 是一种非常轻量级的执行线程。goroutine 是 Go 语言并发模型的核心,允许同时执行多个函数调用。goroutines 在 Go 运行时环境中被多路复用到少量的操作系统(OS)线程上,以实现高效并发。
Lemon黄
2023/12/13
4820
Go 运行时面试题
Golang 需要注意的知识点
(2) 内存占用小: 线程栈空间通常是2M, Goroutine 栈空间最小是2k, golang 可以轻松支持1w+的goroutine运行,而线程数量到达1k(此时基本就达到单机瓶颈了), 内存占用就到2G。
_春华秋实
2025/01/21
1460
Golang 需要注意的知识点
谈谈对 GMP 的简单认识
犹记得最开始学习 golang 的时候,大佬们分享 GMP 模型的时候,总感觉云里雾里,听了半天,并没有一个很清晰的概念,不知 xmd 是否会有这样的体会
阿兵云原生
2023/09/01
3100
谈谈对 GMP 的简单认识
golang 面试总结
前段时间找工作搜索 golang 面试题时,发现都是比较零散或是基础的题目,覆盖面较小。而自己也在边面试时边总结了一些知识点,为了方便后续回顾,特此整理了一下。
lincoln
2022/02/08
9670
golang 面试总结
Go调度系列--调度器实现原理(二)
Go 语言在并发编程方面有强大的能力,这离不开语言层面对并发编程的支持,Go调度的本质就是将 Goroutine (G)按照一定算法放到CPU上去执行。在上一篇我们已经知道了GMP各自代表的含义,三者之间的关系,今天从调度的角度去看Go是如何将三者之间进行协作的。
小许code
2023/03/20
6060
Go调度系列--调度器实现原理(二)
了解go在协程调度上的改进
协作式调度是指以多个任务之间以协作的方式切换执行,每个任务执行一会,任务执行到某个点时会自己让出当前资源交给其他正在等待的任务,这显得比较主动和自愿。
秋名山白又白
2022/01/23
1.5K0
了解go在协程调度上的改进
Golang 协程 与 Java 线程池的联系
如何理解Golang的协程,我觉得可以用一句话概括: Golang 提供的协程是一种支持任务分时复用的高级线程池实现。
大忽悠爱学习
2023/10/19
4790
Golang 协程 与 Java 线程池的联系
相关推荐
字节一面:go的协程比线程轻量,体现在哪?
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档