go语言GMP模式介绍以及协程案例展示

一. MPG模式

Go语言的调度模型被称为GMP,这是一个高效且复杂的调度系统,用于在可用的物理线程上调度goroutines(Go的轻量级线程)。GMP模型由三个主要组件构成:Goroutine、M(机器)和P(处理器)。下面详细介绍这三个组件以及它们如何协同工作。

1. Goroutine(G)

  • Goroutine 是Go语言中的一个基本概念,类似于线程,但比线程更轻量。Goroutines在Go的运行时环境中被调度和管理,而非操作系统。
  • Goroutines非常轻量,启动快,且切换开销小。这是因为它们有自己的栈,这个栈可以根据需要动态增长和缩减。

2. Machine(M)

  • M 代表了真正的操作系统线程。每个M都由操作系统调度,并且拥有一个固定大小的内存栈用于执行C代码。
  • M负责执行Goroutines的代码。Go的运行时会尽量复用M,以减少线程的创建和销毁带来的开销。

3. Processor(P)

  • P 是Go运行时的一个资源,可以看作是执行Goroutines所需的上下文环境。P的数量决定了系统同时运行Goroutines的最大数量。
  • 每个P都有一个本地的运行队列,用于存放待运行的Goroutines。
  • P的数量一般设置为等于机器的逻辑处理器数量,以充分利用多核的优势。

MPG 工作方式

  • 在程序启动时,Go运行时会根据可用的核心数创建一定数量的P。
  • 每个P都会与一个M绑定在一起,这个M会从P的本地运行队列中取出一个G来执行。
  • 当Goroutine阻塞时(比如等待I/O),执行它的M会被解绑,并且该Goroutine会被移动到全局队列或者等待队列中,让其他M可以接管这个P并继续执行其他Goroutines。
  • 如果所有的M都阻塞了,运行时会创建额外的M来保证至少有一个M是非阻塞的,以继续执行Goroutines。

调度优势

  • Go调度器的设计使得成千上万的Goroutines能够在数量较少的线程(M)上高效运行,这极大地减少了上下文切换的开销。
  • Go的调度器是协作式的,这意味着Goroutines需要自己释放控制权。通常,这发生在显式的阻塞操作(如I/O操作)或者隐式的调度点(如函数调用)时。

二.互斥锁实现阶乘计算

1.代码

package mainimport ("fmt""sync"
)// 多协程计算阶乘var (myMap = make(map[int]int) // 全局变量mu    sync.Mutex          // 安全访问myMapwg    sync.WaitGroup      // 等待所有协程完成
)func main() {// 开启协程for i := 1; i <= 10; i++ {wg.Add(1)go factorial(i)}// 等待所有协程完成后再打印wg.Wait()// 遍历myMap并打印结果for i, v := range myMap {fmt.Println(i, v)}
}// 计算阶乘
func factorial(n int) {res := 1// 计算阶乘for i := 1; i <= n; i++ {res *= i}// 递延地减少WaitGroup计数器defer wg.Done()// 在修改myMap之前进行互斥锁操作mu.Lock()myMap[n] = resmu.Unlock()
}

2.MPG模型解释

Go语言的并发模型被称为MPG模型,其中:

  • M 代表机器(Machine),是对操作系统线程的抽象。
  • P 代表处理器(Processor),是对M进行调度的上下文。
  • G 代表Goroutine,是Go的轻量级线程,它在M上执行。

当一个Go程序运行时:

  1. Goroutines(G) 在**Processors(P)**上被调度。每个P都绑定到一个M(操作系统线程),但一个P可以调度多个G。
  2. 在这段代码中,当main函数启动多个goroutines时,这些G被分配到不同的P上,并且可能在不同的M上执行。
  3. 当一个G在执行阶乘计算时,如果它需要等待(例如,等待互斥锁),它会被P挂起,并且P会转而执行另一个G。
  4. 一旦所有的G都执行完毕(即wg.Wait()返回),程序进入最后阶段,遍历并打印myMap中存储的结果。

3.管道channel基本概念

创建管道
  • 使用make关键字创建管道。可以创建有缓冲的管道或无缓冲的管道。
  • 示例:ch := make(chan int) 创建一个传递整型数据的无缓冲管道。
  • 无缓冲管道:这种管道没有存储空间,因此发送操作(ch <- v)会阻塞,直到另一端有goroutine准备好接收(<-ch)。无缓冲管道确保同时只有一个数据在通道中传递,它强制发送者和接收者同步交换数据。
  • 有缓冲管道:这种管道有一个指定的容量,允许在接收者准备好接收之前存储有限数量的值。如果管道满了(即达到其容量限制),发送操作将阻塞;如果管道为空,接收操作将阻塞。有缓冲管道提供了一定程度的松耦合,允许发送者和接收者在缓冲区不满和不空的情况下独立操作。
发送和接收数据
  • 使用箭头操作符(<-)来发送和接收数据。
  • 示例:ch <- v 表示将值v发送到管道chv := <-ch 表示从管道ch接收值并赋给变量v
无缓冲与有缓冲
  • 无缓冲管道:发送操作会阻塞,直到另一端有goroutine进行接收操作。
  • 有缓冲管道:只有当缓冲区满时发送操作才会阻塞,只有当缓冲区空时接收操作才会阻塞。
使用场景
  • 同步:管道可用于不同goroutines之间的同步。
  • 数据共享:通过管道安全地在goroutines之间传递数据,防止竞争条件。
  • 流程控制:通过有缓冲管道控制处理速度和压力。
重要特性
  • 安全性:管道在内部实现了必要的同步机制,因此在多个goroutines访问时是安全的。

  • 阻塞性:无缓冲管道在发送或接收时会阻塞,直到另一端准备好。

  • 关闭管道

  • 使用close函数关闭管道。

  • 关闭管道后,不能再向管道发送数据,但仍可以接收管道中已存在的数据。

  • 尝试向已关闭的管道发送数据会引发panic。

  • 范围循环:可以使用for range循环从管道接收数据,直到管道被关闭。

注意事项
  • 死锁:如果不正确使用管道,特别是在管道操作之间没有适当的同步时,可能导致死锁。
  • 资源管理:应确保在不再需要时关闭管道,以避免内存泄漏。

4.管道channel实现阶乘计算

package mainimport ("fmt""sync"
)var (ch  = make(chan int) // FIFO 队列 first in first out 线程安全wg2 sync.WaitGroup   // 用于等待所有goroutine完成
)func main() {for i := 1; i <= 10; i++ {// 添加WaitGroup的计数wg2.Add(1)go calChannel(i)}wg2.Wait() // 等待所有goroutine完成close(ch)  // 关闭通道// 启动一个新的goroutine来打印管道中的值go func() {for v := range ch {fmt.Println(v)}}()}func calChannel(n int) {defer wg2.Done() // 在函数退出时通知WaitGroup// 通过通道计算阶乘res := 1for i := 1; i <= n; i++ {res *= i}ch <- res
}

三. interface{}类型

package mainimport "fmt"func main() {ch := make(chan interface{}, 3)ch <- 88ch <- "i am god"cat := Cat{Name: "小花猫", Age: 4}ch <- catclose(ch)// 丢弃管道中的值<-ch<-chv := <-chfmt.Printf("%T", v)fmt.Println()// 需要类型断言 ∵从管道中取出的值类型实际是interface{}类型 只有空接口类型才可以类型断言val := v.(Cat)fmt.Printf("%v", val.Name)}type Cat struct {Name stringAge  int
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/628992.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

IPv6隧道--GRE隧道

GRE隧道 通用路由封装协议GRE(Generic Routing Encapsulation)可以对某些网络层协议(如IPX、ATM、IPv6、AppleTalk等)的数据报文进行封装,使这些被封装的数据报文能够在另一个网络层协议(如IPv4)中传输。 GRE提供了将一种协议的报文封装在另一种协议报文中的机制,是一…

Linux一条命令换阿里源

要在Linux系统中切换到阿里源&#xff0c;可以使用以下命令。请注意&#xff0c;不同的Linux发行版可能有不同的包管理工具&#xff0c;因此命令可能会有所不同。 对于使用apt的Debian/Ubuntu系统&#xff1a; sudo cp /etc/apt/sources.list /etc/apt/sources.list.backup …

个人网站制作 Part 7 添加用户认证和数据库集成 | Web开发项目

文章目录 &#x1f469;‍&#x1f4bb; 基础Web开发练手项目系列&#xff1a;个人网站制作&#x1f680; 用户认证与数据库集成&#x1f528;添加用户认证&#x1f527;步骤 1: 使用Passport.js &#x1f528;集成数据库&#x1f527;步骤 2: 使用MongoDB和Mongoose &#x1f…

Grafana(二)Grafana 两种数据源图表展示(json-api与数据库)

一. 背景介绍 在先前的博客文章中&#xff0c;我们搭建了Grafana &#xff0c;它是一个开源的度量分析和可视化工具&#xff0c;可以通过将采集的数据分析、查询&#xff0c;然后进行可视化的展示&#xff0c;接下来我们重点介绍如何使用它来进行数据渲染图表展示 Docker安装G…

AIOps探索 | 基于大模型构建高效的运维知识及智能问答平台(2)

前面分享了平台对运维效率提升的重要性和挑战以及基于大模型的平台建设解决方案&#xff0c;新来的朋友点这里&#xff0c;一键回看精彩原文。 基于大模型构建高效的运维知识及智能问答平台&#xff08;1&#xff09;https://mp.csdn.net/mp_blog/creation/editor/135223109 …

【REMB 】翻译:草案remb-03

REMB REMB消息 以及 绝对时间戳选项 在带宽估计中的使用 :an absolute-value timestamp option for use in bandwidth estimatoin. 接收方带宽估计的RTCP消息 REMB 这位大神翻译的更好。 RTCP message for Receiver Estimated Maximum Bitrate draft-alvestrand-rmcat-remb-03…

iOS开发进阶(六):Xcode14 使用信号量造成线程优先级反转问题修复

文章目录 一、前言二、关于线程优先级反转三、优先级反转会造成什么后果四、怎么避免线程优先级反转五、使用信号量可能会造成线程优先级反转&#xff0c;且无法避免六、延伸阅读&#xff1a;iOS | Xcode中快速打开终端6.1 .sh绑定6.2 执行 pod install 脚本 七、延伸阅读&…

Android Activity的启动流程(Android-10)

前言 在Android开发中&#xff0c;我们经常会用到startActivity(Intent)方法&#xff0c;但是你知道startActivity(Intent)后Activity的启动流程吗&#xff1f;今天就专门讲一下最基础的startActivity(Intent)看一下Activity的启动流程&#xff0c;同时由于Launcher的启动后续…

JDBC是什么?你是如何连接数据库的?

JDBC&#xff08;Java Database Connectivity&#xff09;是Java语言中用来规范客户端程序如何访问数据库的应用程序接口&#xff0c;提供了诸如查询和更新数据库中数据的方法。它由一组用Java语言编写的类和接口组成&#xff0c;使得Java程序员可以使用统一的API来连接不同的数…

光伏发电系统的MPPT控制策略研究

摘 要 面对全球日趋严重的能源危机问题&#xff0c;可再生能源的开发和利用得到了人们的高度重 视。其中辐射到地球太阳能资源是十分富饶的&#xff0c;绿色清洁的太阳能不会危害我们的生存 环境&#xff0c;因而受到了人们的广泛利用。光伏发电作为当前利用太阳能的主要方式…

position有哪些值?分别是根据什么定位的?

CSS的position属性有五个值&#xff0c;它们分别是&#xff1a;static、relative、absolute、fixed和sticky。 static&#xff1a;这是默认值&#xff0c;元素按照正常的文档流进行定位。 relative&#xff1a;元素按照正常的文档流进行定位&#xff0c;然后相对于其原始位置…

STM32——DMA知识点及实战总结

1.DMA概念介绍 DMA&#xff0c;全称Direct Memory Access&#xff0c;即直接存储器访问。 DMA传输 将数据从一个地址空间复制到另一个地址空间。 注意&#xff1a;DMA传输无需CPU直接控制传输 2.DMA框图 3.DMA处理过程 外设的 8 个请求独立连接到每个通道&#xff0c;由 DMA_…

YOLOv5改进 | 融合改进篇 | 轻量化CCFM + SENetv2进行融合改进涨点 (全网独家首发)

一、本文介绍 本文给大家带来的改进机制是轻量化的Neck结构CCFM配合SENetv2改进的网络结构进行融合改进,其中CCFM为我本人根据RT-DETR模型一比一总结出来的,文中配其手撕结构图,其中SENetV2为网络结构重构化模块,通过其改进主干从而提取更有效的特征,这两个模块搭配在一起…

Java实现海南旅游景点推荐系统 JAVA+Vue+SpringBoot+MySQL

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 用户端2.2 管理员端 三、系统展示四、核心代码4.1 随机景点推荐4.2 景点评价4.3 协同推荐算法4.4 网站登录4.5 查询景点美食 五、免责说明 一、摘要 1.1 项目介绍 基于VueSpringBootMySQL的海南旅游推荐系统&#xff…

Webservice调用方式解析!

Webservice调用方式解析&#xff01; 大家好&#xff0c;我是免费搭建查券返利机器人赚佣金就用微赚淘客系统3.0的小编&#xff0c;也是冬天不穿秋裤&#xff0c;天冷也要风度的程序猿&#xff01;在今天的文章中&#xff0c;我们将深入研究Webservice的几种调用方式&#xff…

探索单元测试和 E2E 测试:提升软件质量的关键步骤(下)

&#x1f90d; 前端开发工程师&#xff08;主业&#xff09;、技术博主&#xff08;副业&#xff09;、已过CET6 &#x1f368; 阿珊和她的猫_CSDN个人主页 &#x1f560; 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 &#x1f35a; 蓝桥云课签约作者、已在蓝桥云…

探索Redis特殊数据结构:Bitmaps(位图)在实际中的应用

一、概述 Redis官方提供了多种数据类型&#xff0c;除了常见的String、Hash、List、Set、zSet之外&#xff0c;还包括Stream、Geospatial、Bitmaps、Bitfields、Probabilistic&#xff08;HyperLogLog、Bloom filter、Cuckoo filter、t-digest、Top-K、Count-min sketch、Confi…

【机组】算术逻辑运算单元实验的解密与实战

​&#x1f308;个人主页&#xff1a;Sarapines Programmer&#x1f525; 系列专栏&#xff1a;《机组 | 模块单元实验》⏰诗赋清音&#xff1a;云生高巅梦远游&#xff0c; 星光点缀碧海愁。 山川深邃情难晤&#xff0c; 剑气凌云志自修。 ​ 目录 &#x1f33a; 一、 实验目的…

为您的网站添加网站底部美化代码 支持任意网站

将下面代码放在网站底部或者侧边栏&#xff0c;主要是cssjs的代码&#xff01;html格式&#xff01; 在逛 Gitee、Github 等各大代码仓库时&#xff0c;往往能看到以下这种徽章式的网页链接&#xff0c;美观好看又方便&#xff0c;那么这个徽章是如何制作出来的呢&#xff1f;…

区间预测 | Matlab实现BiLSTM-Adaboost-ABKDE的集成双向长短期记忆网络自适应带宽核密度估计多变量回归区间预测

区间预测 | Matlab实现BiLSTM-Adaboost-ABKDE的集成双向长短期记忆网络自适应带宽核密度估计多变量回归区间预测 目录 区间预测 | Matlab实现BiLSTM-Adaboost-ABKDE的集成双向长短期记忆网络自适应带宽核密度估计多变量回归区间预测效果一览基本介绍程序设计参考资料 效果一览 …