Golang的GMP调度模型与源码解析

简介: 【11月更文挑战第11天】GMP 调度模型是 Go 语言运行时系统的核心部分,用于高效管理和调度大量协程(goroutine)。它通过少量的操作系统线程(M)和逻辑处理器(P)来调度大量的轻量级协程(G),从而实现高性能的并发处理。GMP 模型通过本地队列和全局队列来减少锁竞争,提高调度效率。在 Go 源码中,`runtime.h` 文件定义了关键数据结构,`schedule()` 和 `findrunnable()` 函数实现了核心调度逻辑。通过深入研究 GMP 模型,可以更好地理解 Go 语言的并发机制。

一、GMP 调度模型概述


  1. 背景介绍
  • 在 Go 语言中,为了高效地利用多核处理器并管理大量的并发任务,引入了 GMP 调度模型。它是 Go 语言运行时(runtime)系统的核心部分,用于管理和调度 Go 协程(goroutine)。
  • 与传统的操作系统线程调度相比,Go 的 GMP 调度模型能够在少量操作系统线程(OS Thread)的基础上,高效地调度大量的轻量级协程,从而实现高性能的并发处理。
  1. 基本概念
  • G(Goroutine):Go 语言中的协程,是一种轻量级的用户态线程。它由 Go 运行时进行调度,相比操作系统线程,其创建和销毁的成本非常低。例如,在一个网络服务器应用中,可以轻松创建数千个协程来处理并发的客户端连接,而不会像创建数千个操作系统线程那样带来巨大的资源开销。
  • M(Machine):代表操作系统线程。Go 运行时会将协程调度到操作系统线程上执行。M 与操作系统的线程一一对应,它是真正执行计算的实体。
  • P(Processor):可以看作是逻辑处理器。它是连接 G 和 M 的桥梁,每个 P 都有一个本地队列,用于存放等待执行的 G。P 的数量通常与系统的 CPU 核心数相关,通过这种方式可以充分利用多核处理器的性能。

二、GMP 调度模型的工作流程


  1. G 的创建与初始化
  • 当使用go关键字创建一个协程时,Go 运行时会分配一个 G 结构体来表示这个协程。这个 G 结构体包含了协程的栈空间、程序计数器、状态等信息。
  • 例如,go func() { println("Hello, world") }()这个语句会创建一个新的协程,该协程会在合适的时候执行println("Hello, world")这个函数。
  1. G 进入 P 的本地队列
  • 新创建的 G 会被放入一个 P 的本地队列中。如果本地队列已满,它可能会被放入全局队列或者其他的本地队列中。
  • 每个 P 会从自己的本地队列中取出 G 来执行。这样可以减少锁的竞争,提高调度效率,因为每个 P 在大部分时间里都可以独立地从自己的本地队列中获取 G 进行处理。
  1. M 与 P 的关联和 G 的执行
  • 当一个 M 空闲时,它会尝试获取一个 P。如果获取到 P,M 会从 P 的本地队列中取出一个 G 来执行。
  • 在执行 G 的过程中,如果 G 执行了阻塞操作(如系统调用、通道操作等),M 可能会将当前的 G 暂停,并尝试从 P 的本地队列中获取下一个 G 来执行。如果 P 的本地队列中没有 G,M 可能会从全局队列或者其他 P 的本地队列中获取 G。
  1. 调度循环
  • M 会不断地从 P 的本地队列或者其他地方获取 G 并执行,这个过程形成一个调度循环。当 G 执行完成后,M 会将 G 标记为已完成,并可能会从本地队列或者其他地方获取下一个 G 继续执行。

三、GMP 调度模型的源码解析


  1. 关键数据结构
  • runtime.h中的定义
  • 在 Go 的源码中,runtime.h文件包含了很多关键的数据结构定义。例如,struct G结构体定义了协程的各种属性,包括栈指针、状态、调度相关的信息等。
  • struct M结构体定义了与操作系统线程对应的信息,如线程 ID、当前正在执行的 G 等。
  • struct P结构体定义了处理器相关的信息,如本地队列的指针、状态等。
  1. 调度函数
  • schedule()函数
  • 这是 Go 运行时调度的核心函数之一。它主要负责选择下一个要执行的 G。它会首先检查当前 P 的本地队列,如果本地队列中有 G,就从中取出一个 G 进行执行。
  • 如果本地队列中没有 G,它会尝试从全局队列中获取 G。在获取 G 的过程中,会涉及到一些锁的操作,以确保全局队列的并发安全。
  • findrunnable()函数
  • 这个函数用于寻找一个可运行的 G。它会综合考虑本地队列、全局队列以及其他可能的来源(如从其他 P 的本地队列中 “窃取” G)来找到一个可以执行的 G。它的实现细节涉及到复杂的队列操作和调度策略。
  1. 协程的创建和初始化源码
  • runtime/proc.go文件中,newproc()函数负责创建新的协程。它会分配一个新的G结构体,初始化其栈空间和相关的参数,然后将其放入合适的队列(通常是 P 的本地队列)中等待执行。
  • 例如,newproc()函数中的部分代码用于设置新协程的栈空间大小和栈顶指针等,确保协程在执行时有足够的空间来存储局部变量和函数调用信息。
  1. 与操作系统线程的交互
  • Go 语言的运行时需要与操作系统线程进行交互。在runtime/os_linux.go(以 Linux 系统为例)等文件中,有代码用于创建和管理操作系统线程。
  • 当一个 M 需要创建一个操作系统线程时,会调用相关的系统调用(如clone()函数)来创建一个新的线程。同时,在这个线程的启动函数中,会调用 Go 运行时的调度函数,使得这个线程能够参与到协程的调度过程中。


通过深入研究 Go 语言的 GMP 调度模型和相关源码,可以更好地理解 Go 语言高效并发处理的机制,并且在开发高性能的并发程序时能够更加得心应手。

相关文章
|
6月前
|
算法 测试技术 C语言
深入理解HTTP/2:nghttp2库源码解析及客户端实现示例
通过解析nghttp2库的源码和实现一个简单的HTTP/2客户端示例,本文详细介绍了HTTP/2的关键特性和nghttp2的核心实现。了解这些内容可以帮助开发者更好地理解HTTP/2协议,提高Web应用的性能和用户体验。对于实际开发中的应用,可以根据需要进一步优化和扩展代码,以满足具体需求。
610 29
|
7月前
|
机器学习/深度学习 人工智能 算法
DeepSeek技术报告解析:为什么DeepSeek-R1 可以用低成本训练出高效的模型
DeepSeek-R1 通过创新的训练策略实现了显著的成本降低,同时保持了卓越的模型性能。本文将详细分析其核心训练方法。
1021 11
DeepSeek技术报告解析:为什么DeepSeek-R1 可以用低成本训练出高效的模型
|
6月前
|
前端开发 数据安全/隐私保护 CDN
二次元聚合短视频解析去水印系统源码
二次元聚合短视频解析去水印系统源码
180 4
|
6月前
|
JavaScript 算法 前端开发
JS数组操作方法全景图,全网最全构建完整知识网络!js数组操作方法全集(实现筛选转换、随机排序洗牌算法、复杂数据处理统计等情景详解,附大量源码和易错点解析)
这些方法提供了对数组的全面操作,包括搜索、遍历、转换和聚合等。通过分为原地操作方法、非原地操作方法和其他方法便于您理解和记忆,并熟悉他们各自的使用方法与使用范围。详细的案例与进阶使用,方便您理解数组操作的底层原理。链式调用的几个案例,让您玩转数组操作。 只有锻炼思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
|
6月前
|
移动开发 前端开发 JavaScript
从入门到精通:H5游戏源码开发技术全解析与未来趋势洞察
H5游戏凭借其跨平台、易传播和开发成本低的优势,近年来发展迅猛。接下来,让我们深入了解 H5 游戏源码开发的技术教程以及未来的发展趋势。
|
6月前
|
存储 前端开发 JavaScript
在线教育网课系统源码开发指南:功能设计与技术实现深度解析
在线教育网课系统是近年来发展迅猛的教育形式的核心载体,具备用户管理、课程管理、教学互动、学习评估等功能。本文从功能和技术两方面解析其源码开发,涵盖前端(HTML5、CSS3、JavaScript等)、后端(Java、Python等)、流媒体及云计算技术,并强调安全性、稳定性和用户体验的重要性。
|
6月前
|
存储 算法 Java
GoLang GPM模型
本文介绍了 Go 语言中的 goroutine 及其调度器(Go Scheduler)的工作原理。goroutine 并非传统意义上的协程,而是基于两级线程模型实现的轻量级并发单元。文章详细解释了三种主流线程模型(内核级、用户级和两级线程模型)的特点,并重点阐述了 G-P-M 模型(Goroutine、Processor、Machine)的工作机制,包括调度算法、阻塞处理等。通过动态栈管理和高效的调度器,Go 程序能够轻松支持成千上万个并发任务。
120 0
GoLang GPM模型
|
7月前
|
人工智能 自然语言处理 算法
DeepSeek模型的突破:性能超越R1满血版的关键技术解析
上海AI实验室周伯文团队的最新研究显示,7B版本的DeepSeek模型在性能上超越了R1满血版。该成果强调了计算最优Test-Time Scaling的重要性,并提出了一种创新的“弱到强”优化监督机制的研究思路,区别于传统的“从强到弱”策略。这一方法不仅提升了模型性能,还为未来AI研究提供了新方向。
1104 9
|
8月前
|
自然语言处理
高效团队的秘密:7大团队效能模型解析
3分钟了解7大团队效能模型,有效提升团队绩效。
703 7
高效团队的秘密:7大团队效能模型解析
|
6月前
|
负载均衡 JavaScript 前端开发
分片上传技术全解析:原理、优势与应用(含简单实现源码)
分片上传通过将大文件分割成多个小的片段或块,然后并行或顺序地上传这些片段,从而提高上传效率和可靠性,特别适用于大文件的上传场景,尤其是在网络环境不佳时,分片上传能有效提高上传体验。 博客不应该只有代码和解决方案,重点应该在于给出解决方案的同时分享思维模式,只有思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~

推荐镜像

更多