当前位置: 首页 > article >正文

Go并发背后的双引擎:CSP通信模型与GMP调度|Go语言进阶(4)

为什么需要理解CSP与GMP?

当我们启动一个Go程序时,可能会创建成千上万个goroutine,它们是如何被调度到有限的CPU核心上的?为什么Go能够如此轻松地处理高并发场景?为什么有时候我们的并发程序会出现奇怪的性能瓶颈?

这些问题的答案都藏在CSP模型与GMP调度器的协作机制中。

CSP模型:Go并发的理论基础

CSP是什么?

CSP (Communicating Sequential Processes) 是一种并发编程模型,由Tony Hoare在1978年提出。它的核心思想非常简单:

不要通过共享内存来通信,而是通过通信来共享内存。

在CSP模型中,并发实体(在Go中是goroutine)之间没有共享状态,它们通过消息传递(在Go中是channel)进行通信和同步。这种方式显著降低了并发编程的复杂性和错误概率。

channel

Go如何实现CSP?

Go语言通过三个核心元素实现了CSP模型:

  1. Goroutine:轻量级线程,是Go中并发的基本单位
  2. Channel:goroutine之间通信的管道
  3. Select:多路复用,允许goroutine等待多个通信操作
// CSP模式的典型示例
func producer(ch chan<- int) {for i := 0; i < 10; i++ {ch <- i  // 发送消息time.Sleep(100 * time.Millisecond)}close(ch)
}func consumer(ch <-chan int, done chan<- bool) {for num := range ch {  // 接收消息fmt.Println("消费:", num)}done <- true
}func main() {ch := make(chan int, 5)done := make(chan bool)go producer(ch)go consumer(ch, done)<-done  // 等待消费者完成
}

GMP调度器:Go并发的工程实现

CSP是理论模型,而GMP是Go语言实现这一模型的具体机制。

GMP架构解析

GMP代表Go调度器的三个核心组件:

G (Goroutine)

  • 代表一个Go协程,包含栈、指令指针和其他调度相关信息
  • 非常轻量,仅占用2KB内存(可增长)
  • 用户层面的逻辑执行单元

M (Machine)

  • 代表操作系统线程,由操作系统管理
  • 执行goroutine所需的实际计算资源
  • 数量默认限制为10000(可调整)

P (Processor)

  • 代表调度上下文,是连接G和M的桥梁
  • 默认数量等于GOMAXPROCS设置(通常是CPU核心数)
  • 维护本地可运行的goroutine队列

gmp

调度流程详解

Go的调度器遵循以下基本流程:

  1. Goroutine创建:当使用go关键字创建一个新的goroutine时,它会被放入P的本地队列或全局队列

  2. 调度执行:M从与之关联的P获取G执行

    • 首先从P的本地队列获取
    • 如果本地队列为空,从全局队列窃取
    • 如果全局队列也为空,从其他P窃取(work stealing)
  3. 系统调用:当G执行系统调用时

    • 如果是非阻塞调用,G继续在M上执行
    • 如果是阻塞调用,M将释放P,G与M绑定等待系统调用返回
    • 系统创建或唤醒其他M接管P继续执行其他G
  4. 抢占式调度:为防止某个G长时间占用M,Go调度器实现了协作式和基于信号的抢占机制

gmp调度过程

CSP与GMP的联动机制

CSP模型和GMP调度器之间存在紧密的联系,它们共同构成了Go并发编程的完整图景:

映射关系

  1. CSP中的进程Go中的goroutine (G)

    • CSP模型中的独立顺序进程在Go中就是goroutine
    • 每个goroutine有自己的栈和执行上下文
  2. CSP中的通信Go中的channel

    • CSP的消息传递机制在Go中通过channel实现
    • Channel操作涉及复杂的运行时调度逻辑

联动机制示例

当涉及channel操作时,CSP模型和GMP调度器联动工作:

func main() {ch := make(chan int)go func() {// 发送者goroutinech <- 42}()// 接收者goroutine (main)value := <-chfmt.Println(value)
}

这段代码背后发生了什么:

  1. 主goroutine创建一个channel和一个发送者goroutine
  2. 发送者goroutine被放入P的本地队列等待调度
  3. 主goroutine尝试从空channel接收,被阻塞
  4. 调度器将主goroutine从M上移除,标记为等待状态
  5. M现在可以执行其他goroutine(如刚创建的发送者)
  6. 发送者执行ch <- 42,将数据放入channel并通知调度器
  7. 调度器发现有goroutine在等待此channel,将主goroutine标记为可运行
  8. 主goroutine最终被调度回来,从channel读取值并继续执行

这个过程展示了CSP理论如何通过GMP调度器在Go中得到实现。

最佳实践

  1. 合理设置GOMAXPROCS

    • 默认值等于CPU核心数,通常是最佳选择
    • 对于I/O密集型应用,可以适当增加
    • 可以通过环境变量或运行时调整:runtime.GOMAXPROCS(n)
  2. 避免创建过多goroutine

    • 虽然goroutine很轻量,但数量过多会增加调度开销
    • 使用工作池模式控制并发数量
    func worker(jobs <-chan Job, results chan<- Result) {for job := range jobs {results <- process(job)}
    }func main() {jobs := make(chan Job, 100)results := make(chan Result, 100)// 创建固定数量的workerworkerCount := runtime.NumCPU()for i := 0; i < workerCount; i++ {go worker(jobs, results)}// 发送任务和收集结果// ...
    }
    
  3. 避免长时间占用线程

    • 将CPU密集型计算分解为小块,定期让出控制权
    • 在长循环中使用runtime.Gosched()允许其他goroutine运行
  4. 正确处理阻塞操作

    • 了解哪些操作会导致M阻塞(如某些系统调用)
    • 尽量使用非阻塞I/O和Go标准库(自动处理阻塞问题)

诊断工具

  1. GODEBUG环境变量

    GODEBUG=schedtrace=1000 ./your_program
    

    每1000ms打印一次调度器状态,帮助理解程序运行时的goroutine调度情况

  2. 调度可视化工具

    go tool trace your_program
    

    生成并可视化程序的执行轨迹,直观显示goroutine的调度情况

总结

CSP模型为Go语言提供了简洁优雅的并发编程范式,而GMP调度器则是这一理念在工程上的高效实现。两者紧密配合,使Go成为处理并发最自然的语言之一。

理解CSP与GMP的联动机制,可以帮助我们:

  • 编写更高效的并发代码
  • 避免常见的并发陷阱
  • 更好地诊断和解决性能问题
  • 充分发挥Go语言的并发优势

相关文章:

Go并发背后的双引擎:CSP通信模型与GMP调度|Go语言进阶(4)

为什么需要理解CSP与GMP&#xff1f; 当我们启动一个Go程序时&#xff0c;可能会创建成千上万个goroutine&#xff0c;它们是如何被调度到有限的CPU核心上的&#xff1f;为什么Go能够如此轻松地处理高并发场景&#xff1f;为什么有时候我们的并发程序会出现奇怪的性能瓶颈&…...

docker内安装达梦8数据库

1. 其他机器上实现挂载ISO # 1. 确保挂载点目录存在&#xff08;你已经创建了dm8目录&#xff09; ls -ld dm8# 2. 使用正确的mount命令挂载ISO sudo mount -o loop dm8_20250117_HWarm920_kylin10_sp1_64.iso dm8# 3. 验证是否挂载成功 mount | grep dm8 ls dm82. docker内运…...

UDP怎么样实现可靠传输?

如果需要在基于UDP的应用中实现可靠传输&#xff08;例如确保数据不丢失、按顺序到达等&#xff09;&#xff0c;通常需要在应用层实现相应的机制。 1. 确认应答机制 应用层可以使用确认应答机制来确保数据的可靠传输。当发送方发送一个数据包时&#xff0c;接收方收到数据包…...

代码随想录算法训练营Day25

一、力扣93.复原IP地址【medium】 题目链接&#xff1a;力扣93.复原IP地址 left x300 视频链接&#xff1a;代码随想录 1、思路 时间复杂度&#xff1a; O ( n ) O(n) O(n) 2、代码 class Solution:def restoreIpAddresses(self, s: str) -> List[str]:n len(s)ans []…...

Linux服务器——Samba服务器

简介 Samba 是一个开源的跨平台文件共享服务​​&#xff0c;允许 Linux/Unix 系统与 Windows 系统实现文件和打印机的共享与互操作。其核心协议为 ​​SMB/CIFS​​&#xff08;Server Message Block / Common Internet File System&#xff09;&#xff0c;是 Windows 网络中…...

华为网路设备学习-17

目录 一、加密算法 二、验证算法 三、IPsec协议 1.IKE协议&#xff08;密钥交换协议&#xff09; ①‌ISAKMP&#xff08;Internet Security Association and Key Management Protocol&#xff09;互联网安全关联和密钥管理协议 ②安全关联&#xff08;SA&#xff09; ③…...

各开源协议一览

在 GitHub 上&#xff0c;开源项目通常会使用一些常见的开源协议来定义项目的使用、修改和分发规则。以下是目前 GitHub 上最常见的几种开源协议及其差异和示例说明&#xff1a; TL;DR 协议宽松程度是否强制开源专利保护适用场景MIT最宽松否无希望代码被广泛使用Apache 2.0宽松…...

解决python manage.py shell ModuleNotFoundError: No module named xxx

报错如下&#xff1a; python manage.py shellTraceback (most recent call last):File "/Users/z/Documents/project/c/manage.py", line 10, in <module>execute_from_command_line(sys.argv)File "/Users/z/.virtualenvs/c/lib/python3.12/site-packa…...

机器学习12-集成学习-案例

参考 【数据挖掘】基于XGBoost的垃圾短信分类与预测 【分类】使用XGBoost算法对信用卡交易进行诈骗预测 银行卡电信诈骗危险预测(LightGBM版本) 【数据挖掘】基于XGBoost的垃圾短信分类与预测 基于XGBoost的垃圾短信分类与预测 我分享了一个项目给你《【数据挖掘】基于XG…...

使用Ubuntu18恢复群晖nas硬盘数据外接usb

使用Ubuntu18恢复群晖nas硬盘数据外接usb 1. 接入硬盘2.使用Ubuntu183.查看nas硬盘信息3. 挂载nas3.1 挂载损坏nas硬盘(USB)3.2 挂载当前运行的nas 4. 拷贝数据分批传输 5. 新旧数据对比 Synology NAS 出现故障&#xff0c;DS DiskStation损坏&#xff0c;则可以使用计算机和 U…...

微服务系统记录

记录下曾经工作涉及到微服务的相关知识。 1. 架构设计与服务划分 关键内容 领域驱动设计&#xff08;DDD&#xff09;&#xff1a; 利用领域模型和限界上下文&#xff08;Bounded Context&#xff09;拆分业务&#xff0c;明确服务边界。通过事件风暴&#xff08;Event Storm…...

【数据库原理及安全实验】实验二 数据库的语句操作

目录 指导书原文 实操备注 指导书原文 【实验目的】 1) 掌握使用SQL语言进行数据操纵的方法。 【实验原理】 1) 面对三个关系表student&#xff0c;course&#xff0c;sc。利用SQL语句向表中插入数据&#xff08;insert&#xff09;&#xff0c;然后对数据进行delete&…...

python 微信小程序支付、查询、退款使用wechatpy库

首先使用 wechatpy 库&#xff0c;执行以下命令进行安装 pip install wechatpy 1、 直连商户支付 import logging from django.http import JsonResponse from django.views.decorators.http import require_http_methods from wechatpy.pay import WeChatPay from wechatpy.…...

蓝桥杯备赛学习笔记:高频考点与真题预测(C++/Java/python版)

2025蓝桥杯备赛学习笔记 ——高频考点与真题预测 一、考察趋势分析 通过对第13-15届蓝桥杯真题的分析&#xff0c;可以发现题目主要围绕基础算法、数据结构、数学问题、字符串处理、编程语言基础展开&#xff0c;且近年逐渐增加动态规划、图论、贪心算法等较难题目。 1. 基…...

【BFT帝国】20250409更新PBFT总结

2411 2411 2411 Zhang G R, Pan F, Mao Y H, et al. Reaching Consensus in the Byzantine Empire: A Comprehensive Review of BFT Consensus Algorithms[J]. ACM COMPUTING SURVEYS, 2024,56(5).出版时间: MAY 2024 索引时间&#xff08;可被引用&#xff09;: 240412 被引:…...

Linux-CentOS-7—— 配置静态IP地址

文章目录 CentOS-7——配置静态IP地址VMware workstation的三种网络模式配置静态IP地址1. 编辑虚拟网络2. 确定网络接口名称3. 切换到网卡所在的目录4. 编辑网卡配置文件5. 查看网卡文件信息6. 重启网络服务7. 测试能否通网8. 远程虚拟主机&#xff08;可选&#xff09; 其他补…...

Jupyter Lab 无法启动 Kernel 问题排查与解决总结

&#x1f4c4; Jupyter Lab 无法启动 Kernel 问题排查与解决总结 一、问题概述 &#x1f6a8; 现象描述&#xff1a; 用户通过浏览器访问远程服务器的 Jupyter Lab 页面&#xff08;http://xx.xx.xx.xx:8891/lab&#xff09;后&#xff0c;.ipynb 文件可以打开&#xff0c;但无…...

算法训练之位运算

♥♥♥~~~~~~欢迎光临知星小度博客空间~~~~~~♥♥♥ ♥♥♥零星地变得优秀~也能拼凑出星河~♥♥♥ ♥♥♥我们一起努力成为更好的自己~♥♥♥ ♥♥♥如果这一篇博客对你有帮助~别忘了点赞分享哦~♥♥♥ ♥♥♥如果有什么问题可以评论区留言或者私信我哦~♥♥♥ ✨✨✨✨✨✨ 个…...

linux入门三:Linux 编辑器

一、轻量级编辑器&#xff1a;快速上手的首选 1.1 Leafpad&#xff1a;极简主义的轻量之选 核心特点 轻量快速&#xff1a;体积小、启动快&#xff0c;资源占用极低&#xff0c;适合低配设备或快速编辑简单文件。 无复杂功能&#xff1a;仅支持基础文本编辑&#xff0c;界面…...

C++设计模式+异常处理

#include <iostream> #include <cstring> #include <cstdlib> #include <unistd.h> #include <sstream> #include <vector> #include <memory> #include <stdexcept> // 包含异常类using namespace std;// 该作业要求各位写一…...

HttpServletRequest是什么

HttpServletRequest 是 Java Servlet API 中的一个接口&#xff0c;表示 HTTP 请求对象。它封装了客户端&#xff08;如浏览器&#xff09;发送到服务器的请求信息&#xff0c;并提供了访问这些信息的方法。 1. 基本概念 作用&#xff1a; HttpServletRequest 提供了一种机制&…...

checkra1n越狱出现的USB error -10问题解决

使用checkra1n进行越狱是出现&#xff1a; 解决办法(使用命令行进行越狱)&#xff1a; 1. cd /Applications/checkra1n.app/Contents/MacOS 2. ./checkra1n -cv 3. 先进入恢复模式 a .可使用爱思助手 b. 或者长按home,出现关机的滑条&#xff0c;同时按住home和电源键&#…...

golang-defer延迟机制

defer延迟机制 defer是什么 defer是go中一种延迟调用机制。 执行时机 defer后面的函数只有在当前函数执行完毕后才能执行。 执行顺序 将延迟的语句按defer的逆序进行执行&#xff0c;也就是说先被defer的语句最后被执行&#xff0c;最后被defer的语句&#xff0c;最先被执…...

【小沐学Web3D】three.js 加载三维模型(Angular)

文章目录 1、简介1.1 three.js1.2 angular.js 2、three.js Angular.js结语 1、简介 1.1 three.js Three.js 是一款 webGL&#xff08;3D绘图标准&#xff09;引擎&#xff0c;可以运行于所有支持 webGL 的浏览器。Three.js 封装了 webGL 底层的 API &#xff0c;为我们提供了…...

一种替代DOORS在WORD中进行需求管理的方法 (二)

一、前景 参考&#xff1a; 一种替代DOORS在WORD中进行需求管理的方法&#xff08;基于WORD插件的应用&#xff09;_doors aspice-CSDN博客 二、界面和资源 WORD2013/WORD2016 插件 【已使用该工具通过第三方功能安全产品认证】&#xff1a; 1、 核心功能 1、需求编号和跟…...

一个基于ragflow的工业文档智能解析和问答系统

工业复杂文档解析系统 一个基于ragflow的工业文档智能解析和问答系统,支持多种文档格式的解析、知识库管理和智能问答功能。 系统功能 1. 文档管理 支持多种格式文档上传(PDF、Word、Excel、PPT、图片等)文档自动解析和分块处理实时处理进度显示文档解析结果预览批量文档…...

23种设计模式-行为型模式-访问者

文章目录 简介场景解决完整代码核心实现 总结 简介 访问者是一种行为设计模式&#xff0c;它能把算法跟他所作用的对象隔离开来。 场景 假如你的团队开发了一款能够使用图像里地理信息的应用程序。图像中的每个节点既能代表复杂实体&#xff08;例如一座城市&#xff09;&am…...

WebView2最低支持.NET frame4.5,win7系统

WebView2最低支持.NET frame什么版本 ‌WebView2 对 .NET Framework 的最低版本要求‌ ‌基础支持范围‌ WebView2 官方支持的 .NET Framework ‌最低版本为 4.5‌&#xff0c;同时兼容 ‌.NET Core 3.0‌ 及以上版本‌18。对于 WPF、WinForms 等桌面应用开发&#xff0c;需确…...

WHAT - React 组件的 props.children 属性

目录 一、什么是 children二、基本用法三、类型定义&#xff08;TypeScript&#xff09;四、一些高级用法1. 条件渲染 children2. 多个 children 插槽&#xff08;命名插槽&#xff09; 五、children 的优势总结 在 React 中&#xff0c;children 是一个非常重要且特殊的 内置属…...

组播网络构建:IGMP、PIM 原理及应用实践

IP组播基础 组播基本架构 组播IP地址 一个组播IP地址并不是表示具体的某台主机&#xff0c;而是一组主机的集合&#xff0c;主机声明加入某组播组即标识自己需要接收目的地址为该组播地址的数据IP组播常见模型分为ASM模型和SSM模型ASM&#xff1a;成员接收任意源组播数据&…...