六、Golang的并发

news/2024/5/20 12:31:37/文章来源:https://blog.csdn.net/weixin_44014982/article/details/130324065

Go语言的并发指的是能让某个函数独立于其他函数运行的能力。当一个函数创建为goroutine时,Go会将其视为一个独立的工作单元。这个单元会被调度到可用的逻辑处理器上执行。
Go语言运行时的调度器是一个复杂的软件,能管理被创建的所有goroutine并为其分配执行时间。这个调度器在操作系统之上,将操作系统的线程与语言运行时的逻辑处理器绑定,并在逻辑处理器上运行goroutine。调度器在任何给定的时间,都会全面控制哪个goroutine要在哪个逻辑处理器上运行。
Go语言的并发同步模型来自一个叫做通信顺序进程 (CSP)的范型。CSP是一种消息传递类型,通过在goroutine之间传递数据来传递消息,而不是对数据进行加锁来实现同步访问。用于在goroutine之间同步和传递数据的关键数据类型叫做通道

一、并发与并行
操作系统会在物理处理器上调度线程来运行,而Go语言的运行时会在逻辑处理器上调度goroutine来运行。每个逻辑处理器都分别绑定到单个操作系统线程。这些逻辑处理器会用于执行所有被创建的goroutine。即便只有一个逻辑处理器,Go也可以以神奇的效率和性能,并发调度无数个goroutine。
下图展示了Go调度器如何管理goroutine。
在这里插入图片描述
可以看到操作系统线程、逻辑处理器和本地运行队列之间的关系。如果创建一个goroutine并准备运行,这个goroutine就会被放到调度器的全局运行队列中。之后,调度器就将这些队列中的goroutine分配给一个逻辑处理器,并放到这个逻辑处理器对应的本地运行队列中。本地运行队列中的goroutine会一直等待直到自己被分配的逻辑处理器执行。
有时,正在运行的goroutine需要执行一个阻塞的系统调用,如打开一个文件。当这类调用发生时,线程和goroutine会从逻辑处理器上分离,该线程会继续阻塞,等待系统调用的返回。与此同时,这个逻辑处理器就失去了用来运行的线程。所以,调度器会创建一个新线程,并将其绑定到该逻辑处理器上。之后,调度器会从本地运行队列里选择另一个goroutine来执行。一旦被阻塞的系统调用执行完成并返回,对应的goroutine会放回到本地运行队列,而之前的线程会保存好,以便之后可以继续使用。
并发不是并行。并行是让不同的代码片段同时在不同的物理处理器上执行。并行的关键是同时做很多事情,而并发是同时管理很多事情,这些事情可能只做了一半就被暂停去做别的事情了。

二、goroutine
下面来看一个样例,创建两个goroutine以并发形式分别显示大写和小写的英文字母。

package mainimport ("fmt""runtime""sync"
)func main() {//分配一个逻辑处理器给调度器使用//GOMAXPROCS允许程序更改调度器可以使用的逻辑处理器的数量runtime.GOMAXPROCS(1)//wg用来等待程序完成、计数加2,表示要等待两个goroutinevar wg sync.WaitGroupwg.Add(2)fmt.Println("Start Goroutines")//声明一个匿名函数,并创建一个goroutinego func() {//在函数退出时调用Done来通知main函数工作已经完成defer wg.Done()//显示三次字母表for count := 0; count < 3; count++ {for char := 'a'; char <= 'z'; char++ {fmt.Printf("%c ", char)}}}()go func() {//在函数退出时调用Done来通知main函数工作已经完成defer wg.Done()for count := 0; count < 3; count++ {for char := 'A'; char <= 'Z'; char++ {fmt.Printf("%c ", char)}}}()//等待goroutine结束fmt.Println("Waiting To Finish")wg.Wait()fmt.Println("\nTerminating Program")
}

三、竞争状态
如果两个或者多个goroutine在互相没有同步的情况下,访问某个共享的资源,并试图同时读和写这个资源,就处于相互竞争的状态,这种情况被称作竞争状态。所以对一个共享资源的读和写操作必须是原子化的。

四、锁住共享资源
Go语言提供了传统的同步goroutine的机制,就是对共享资源加锁。如果需要顺序访问一个整型变量或者一段代码,atomic和sync包里的函数提供了很好的解决方案。
1、原子函数
原子函数能够以很底层的加锁机制来同步访问整型变量和指针。下面是一个使用原子函数修正竞争状态的示例。

package mainimport ("fmt""runtime""sync""sync/atomic"
)var (//counter是所有goroutine都要增加其值的变量counter int64//wg用来等待程序结束wg sync.WaitGroup
)func main() {//计数加2,表示要等待两个goroutinewg.Add(2)//创建两个goroutinego incCounter(1)go incCounter(2)//等待goroutiine结束wg.Wait()//显示最终的值fmt.Println("Final Counter:", counter)
}func incCounter(id int) {defer wg.Done()for count := 0; count < 2; count++ {//安全地对counter加1//AddInt方法强制同一时刻只能有一个goroutine运行并完成这个加法操作//类似的函数还有LoadInt64,StoreInt64atomic.AddInt64(&counter, 1)//当前goroutine从线程退出,并放回到队列runtime.Gosched()}
}

2、互斥锁
互斥锁用于在代码上创建一个临界区,保证同一时间只有一个goroutine可以执行这个临界区代码。

func incCounter(id int) {defer wg.Done()for count := 0; count < 2; count++ {//同一时刻只允许一个goroutine进入mutex.Lock(){//捕获counter的值value := counter//当前goroutine从线程退出,并放回队列runtime.Gosched()//增加本地value值value++//保存回countercounter = value}mutex.Unlock()//释放锁,允许其他正在等待的goroutine}
}

对counter的操作在Lock()和Unlock()函数调用定义的临界区里被保护起来。使用大括号不是必须的。同一时刻只有一个goroutine可以进入临界区。

五、通道
除了上述方法,你还可以使用通道,通过发送和接收需要共享的资源,在goroutine之间做同步。

使用make创建通道

//无缓冲的整型通道
unbuffere := make(chan int)
//有缓冲的字符串通道
buffered := make(chan string, 10)

向通道发送值

//有缓冲的字符串通道
buffered := make(chan string, 10)
//通过通道发送一个字符串
buffered <- "Gopher"
//从通道接受值
value := <-buffered

1、无缓冲的通道指接受前没有能力保存任何值的通道。这种类型的通道强制要求goroutine之间必须同时完成发送和接收。
2、有缓冲的通道是一种在被接收前能存储一个或多个值的通道。这种类型的通道并不强制要求goroutine之间必须同时完成发送和接收。

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

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

相关文章

Spring之Bean的配置与实例

Spring之Bean的配置与实例 一、Bean的基础配置1. Bean基础配置【重点】配置说明代码演示运行结果 2. Bean别名配置配置说明代码演示打印结果 3. Bean作用范围配置【重点】配置说明代码演示打印结果 二、Bean的实例化1. Bean是如何创建的2. 实例化Bean的三种方式2.1 构造方法方式…

NewBing 边栏快捷插件没有了!如何解决?如何脱离浏览器使用 New Bing?

作者&#xff1a;明明如月学长&#xff0c; CSDN 博客专家&#xff0c;蚂蚁集团高级 Java 工程师&#xff0c;《性能优化方法论》作者、《解锁大厂思维&#xff1a;剖析《阿里巴巴Java开发手册》》、《再学经典&#xff1a;《EffectiveJava》独家解析》专栏作者。 热门文章推荐…

[世界读书日] 最好的书,都在博雅之中

今天是世界读书日&#xff08;4月23日&#xff09;&#xff0c;还是谈谈读书。 我很少看到有人说读书不好的&#xff0c;但很少看到有人爱读书&#xff0c;也很少看到有人读到了好书。 好书、好读书、读好书&#xff0c;都是很稀缺的。 一、好书的作用 基本上&#xff0c;我们遇…

NFC 学习笔记 5 MFRC522读写器2 NDEF

NDEF简介 NDEF&#xff08;NFC Data Exchange Format&#xff09;是一种标准化的数据格式&#xff0c;用于将数据存储在NFC标签或智能手机中。该格式是NFC论坛定义的&#xff0c;目的是在不同的NFC设备之间交换信息。 NDEF格式可以存储各种类型的数据&#xff0c;例如URL、文本…

参数与非参数检验:理解差异并正确使用

数据科学是一个快速发展的领域&#xff0c;它在很大程度上依赖于统计技术来分析和理解复杂的数据集。这个过程的一个关键部分是假设检验&#xff0c;它有助于确定从样本中获得的结果是否可以推广到总体。 在这篇文章中&#xff0c;我们将探讨参数与非参数检验之间的区别&#…

第3章:select

1.最基本的select语句 select … from…select 字段1&#xff0c;字段2&#xff0c;…from 表名* 表中所有字段&#xff08;列&#xff09; 2.列的别名 字段1 as 别名1字段1 别名1as&#xff1a;alias&#xff08;别名&#xff09;可以省略如果别名有空格使用一对””引起来…

pycharml利用ddddocr和selenium识别验证码并登录

文章目录 1OCR2 ddddocr3使用案例4 常见问题代码详情获得XPATH方法 1OCR OCR (Optical Character Recognition&#xff0c;光学字符识别)&#xff0c;是指电子设备(例如扫描仪或 数码相机)检查纸上打印的字符&#xff0c;通过检测暗、亮的模式确定其形状&#xff0c;然后用字符…

[Platforimio] LVGL +TFT_eSPI实现触摸功能

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; 本人持续分享更多关于电子通信专业内容以及嵌入式和单片机的知识&#xff0c;如果大家喜欢&#xff0c;别忘点个赞加个关注哦&#xff0c;让我们一起共同进步~ &#x…

【LeetCode训练营】反转链表 移除链表元素 详细图解 203,206

&#x1f48c; 博客内容&#xff1a;LeetCode 训练营 &#x1f600; 作  者&#xff1a;陈大大陈 &#x1f680; 个人简介&#xff1a;一个正在努力学技术的准前端&#xff0c;专注基础和实战分享 &#xff0c;欢迎私信&#xff01; &#x1f496; 欢迎大家&#xff1a;这…

谁在成为产业经济发展的推车人?

区域发展的新蓝图中&#xff0c;京东云能做什么&#xff1f;它的角色是什么&#xff1f;这个问题背后&#xff0c;隐藏的不仅是京东云自身的能力和价值&#xff0c;更是其作为中国互联网云厂商的代表之一&#xff0c;对“技术产业”的新论证。 作者|皮爷 出品|产业家 关于云…

配置zabbix自定义监控项

1.需要安装zabbix-agent服务&#xff0c;使用的zabbix版本为5.0版本 参考&#xff1a;zabbix监控linux主机_Apex Predator的博客-CSDN博客 2.创建存放脚本目录并编辑监控服务的脚本(此处监控一下服务是否存活) mkdir /opt/zabbix_jb vi /opt/zabbix_jb/service_status.sh …

进阶必看 | 有关BIMer强推的5本书,看过的都竖大拇指!

大家好&#xff0c;还是我&#xff0c;建模助手。 本期的主题都是围绕着&#xff1a;热点。除了建模助手的品牌资讯之外&#xff0c;还有一些与行业相关的热点。 这不&#xff0c;4月23日是正好的世界读书日&#xff0c;给大家搞一波书籍推荐&#xff01; 小编认为&#xff…

24从零开始学Java之如何正确地使用一维数组

作者&#xff1a;孙玉昌&#xff0c;昵称【一一哥】&#xff0c;另外【壹壹哥】也是我哦 千锋教育高级教研员、CSDN博客专家、万粉博主、阿里云专家博主、掘金优质作者 前言 在之前的文章中&#xff0c;壹哥给大家讲解了java里的顺序结构、分支结构、循环结构等内容&#xff0…

pytest使用 一(安装、简单的测试用例、运行)

Pytest框架 — 1.Pytest测试框架介绍 - 知乎 2023最新pytest接口自动化测试框架&#xff0c;三天带你精通pytest&#xff0c;带你写出最好的代码&#xff01;&#xff08;已更新2023新版&#xff09;_哔哩哔哩_bilibili 一、pytest安装 pip3 install pytest # 查看pytest版本…

【蓝桥杯省赛真题19】python完数及个数 青少年组蓝桥杯python编程省赛真题解析

目录 python完数及个数 一、题目要求 1、编程实现 2、输入输出 二、解题思路

Python 基础(十一):集合

❤️ 博客主页&#xff1a;水滴技术 &#x1f338; 订阅专栏&#xff1a;Python 入门核心技术 &#x1f680; 支持水滴&#xff1a;点赞&#x1f44d; 收藏⭐ 留言&#x1f4ac; 文章目录 一、声明集合1.1、使用 {} 声明集合1.2、声明空的集合1.3、自动过滤重复元素 二、添加…

隐私计算,联邦学习

隐私计算&#xff08;“隐私保护计算” Privacy-Preserving Computation&#xff09; 隐私计算是一类技术方案&#xff0c;在处理和分析计算数据的过程中能保持数据不透明、不泄露、无法被计算方法以及其他非授权方获取。 数据方是指为执行隐私保护计算过程提供数据的组织或个…

MP长篇综述 | 植物泛基因组及其应用

2022年12月15日&#xff0c;中山大学史俊鹏副教授、中国科学院遗传与发育生物学研究所田志喜研究员、中国农业大学赖锦盛教授和上海师范大学黄学辉教授共同撰文&#xff0c;在Molecular Plant杂志发表了题为“Plant pan-genomics and its applications”的长篇综述。该论文对植…

github 基础

github 基础 前面讲了 git 的基本使用&#xff0c;这里简单的提一下 github 的基本使用&#xff0c;主要还是 pull 和 push 两个部分。其中 pull 好像有了一些变化&#xff0c;现在似乎是需要 rebase 而不是自动就帮你做了……&#xff1f;不过 rebase 的部分之后再提。 当然…

Echarts渲染行政区划,实现聚焦高亮交互

首先需要准备行政区划的JSON数据&#xff0c;可以在DataV获取省市区的JSON数据。 最终效果图 渲染地图 建立一个地图容器&#xff0c;注意要给宽高 <!-- 地图容器 --> <div id"map"></div>请求JSON数据&#xff0c;渲染地图 $(function() {var …