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

Go并发编程(上)

目录

一、go语言当中的协程

二、MPG模型介绍

三、Goroutine  的使用

 3.1  协程的开启

3.2 优雅地等待子协程结束

四、捕获子协程的panic

五、管道Channel

5.1、认识管道

5.2、Channel的遍历和关闭

5.3 、用管道实现生产者消费者模型

5.4、Channel一些使用细节和注意事项


一、go语言当中的协程

在C++中我们要实现并发编程的时候,我们通常需要自己维护一个线程池,并且需要自己去包装一个又一个的任务,同时需要自己去调度线程执行任务并维护上下文切换,这一切通常会耗费程序员大量的心智。那么能不能有一种机制,程序员只需要定义很多个任务,让系统去帮助我们把这些任务分配到CPU上实现并发执行呢?

Go语言中的goroutine就是这样一种机制,goroutine的概念类似于线程,但 goroutine是由Go的运行时(runtime)调度和管理的。Go程序会智能地将 goroutine 中的任务合理地分配给每个CPU。Go语言之所以被称为现代化的编程语言,就是因为它在语言层面已经内置了调度和上下文切换的机制


Go语言编程中你不需要去自己写进程、线程、协程,你的技能包里只有一个技能–goroutine,当你需要让某个任务并发执行的时候,你只需要把这个任务包装成一个函数,开启一个goroutine去执行这个函数就可以了,就是这么简单粗暴

二、MPG模型介绍

我们先来看一下Go语言的并发模式,发现是不同于C++的

下面我们来解释一下MPG模式当中的M、P、G分别代表什么意思

模型解释:

G0, G1,G2  谁先执行完是完全不确定的,这不像是java语言,java可以给每个线程分别设置一个优先级,然后控制线程的执行顺序,但是go的话是不行的。  程序员只能把一个协程开启,但是中间的过程是无法去决定的。

三、Goroutine  的使用

 3.1  协程的开启

两种方法开启,当然这里只是开启,并没有去等待协程的结束。

3.2 优雅地等待子协程结束

父协程结束后,子协程并不会结束。main协程结束后,所有协程都会结束。

代码演示:

var wg = sync.WaitGroup{}func Add() {defer wg.Done()time.Sleep(1 * time.Second)fmt.Println("over")
}func main() {wg.Add(2)go Add() //开启了一个协程,并没有等待结束go Add()wg.Wait()
}

四、捕获子协程的panic

何时会发生panic:

  • 运行时错误会导致panic,比如数组越界、除0。

  • 程序主动调用panic(error)。

panic会执行什么:

  1. 逆序执行当前goroutine的defer链(recover从这里介入)。

  2. 打印错误信息和调用堆栈。

  3. 调用exit(2)结束整个进程。

关于defer

  • defer在函数退出前被调用,注意不是在代码的return语句之前执行,因为return语句不是原子操作。

  • 如果发生panic,则之后注册的defer不会执行。

  • defer服从先进后出原则,即一个函数里如果注册了多个defer,则按注册的逆序执行。

  • defer后面可以跟一个匿名函数。

五、管道Channel

5.1、认识管道

管道其本质上是一个环形队列,在这里说明一下定义管道有以下节点需要注意

1.hannel本质就是一个数据结构-环形队列
2.数据是先进先出[FIFO : [first in first out]
3.线程安全,多goroutine访问时,不需要加锁,就是说channel本身就是线程安全的(编译器底部维护的)

4.channel有类型的,一个string的channel只能存放string类型数据

下面我们来看看如何定义管道

var intChan chan int //intChan用来存储int数据var mapChan chan map[int]string//mapChan用来存储map[int]string类型var perChan chan People//用来存储自定义类型Peoplevar perChan2 chan *People

在这里有以下几点需要注意

  • 管道channel 是引用类型,需要初始化以后才能插入数据,也就是make
  • 管道是有类型的,管道的类型是什么就只能写入这种类型的数据
  • 当管道写满了以后,在没有别的协程的情况下,再次写入会导致死锁
  • 在没有使用协程的情况下(取完没放入),当管道为空,再取,会报deadlock
  • 遍历管道时需要提前把管道关闭(close),否则会导致死锁

代码进行演示

func main() {ch := make(chan int, 5)//创建一个管道for i := 0; i < 5; i++ {ch <- i //在管道当中写入数据}for len(ch) > 0 {value := <-chfmt.Println(value)}ch = make(chan int) //非缓冲通道val := <-ch         //没有初始化就取数据,会发生错误的fmt.Println(val)//注意channel关闭之后不能向channel当中写入数据,否则会造成死锁/*channel支持for --range遍历但是请注意两个细节遍历时如果channel没有关闭则会出现deadlock的错误在遍历时如果channel以及关闭了则会正常的遍历数据,遍历完毕之后就会退出吧遍历*/intchan := make(chan int, 100)for i := 0; i < 100; i++ {intchan <- i//放入100个数据到channel当中}//for i := 0; i < len(intchan); i++ {//	fmt.Println(<-intchan)//	//注意这样会少50个数据所以不能这样遍历管道的长度是一直在变的//}close(intchan) //遍历其一定需要将管道关闭否则会造成死锁for v := range intchan {fmt.Println(v)}
}

5.2、Channel的遍历和关闭

1.channel的关闭:使用内置函数close可以关闭channel,当channel关闭后,就不能再向channel写数据了,但是仍然可以从该channel读取数据,就算读取数据个数大于容量,也能读取到,只是读出来的是0 ,这时候就需要用  v,ok := < - intChan,  如果管道没有关闭,是会阻塞在这一步的,也就是说ok这里不会有值

for {v, ok := <-intChan2if !ok {//证明没有数据了fmt.Println("没有数据了") fmt.Println(v) //  读出来的是0break}fmt.Println(v)}

2.channel支持for-range 遍历和普通for进行遍历,但是普通的for循环遍历, 因为取出操作本身会导致长度变化所以我们不建议使用。

3.在遍历时,如果channel没有关闭,则回出现deadlock的错误。在遍历时,如果channel已经关闭,则会正常遍历数据,遍历完后,就会退出遍历。
 

func main() {intChan := make(chan int, 3)intChan <- 1intChan <- 2close(intChan) //关闭管道//关闭管道后就不能存放了,但是可以取数据x1 := <-intChanx2 := <-intChan//x3 := <-intChan//x4 := <-intChanfmt.Println(x1)fmt.Println(x2)//fmt.Println(x3)//fmt.Println(x4)intChan2 := make(chan int, 100)for i := 0; i < 100; i++ {intChan2 <- i}//遍历管道前切记要先close//不能使用普通的for循环,因为管道的数量在动态变化的 ,但是这里如果提前直到数量是100,循环的话i<100 就行//for i := 0; i < len(intChan2); i++ {//	x := <-intChan2//	fmt.Println(x)//}close(intChan2) //遍历前切记要先关闭管道for v := range intChan2 {fmt.Println(v)}}

5.3 、用管道实现生产者消费者模型

1.开启一个Writea协程,向管道intChan中写入50个整数
2.开启一个Read协程,从管道intChan中读取writeData写入的数据。

3.注意: Write和Read操作的是同一个管道
4.主线程需要等待Write和Read协程都完成工作才能退出[管道]

代码展示:

package mainimport ("fmt"
)func Write(intChan chan int) {for i := 0; i < 50; i++ {fmt.Printf("写入数据 :%d \n", i)intChan <- i}close(intChan) //写完之后关闭管道,但是不影响取
}func Read(intChan chan int, boolChan chan bool) {for {//time.Sleep(time.Millisecond * 100) //先等一秒,为了留时间给生产者,不等可能会直接退出v, ok := <-intChanif !ok { //证明已经没有数据了fmt.Println("管道已经没有数据了。。。")break}fmt.Printf("读出了数据 :%d\n", v)}//任务完成向管道当中写入数据boolChan <- true//通知主线程该结束了close(boolChan)
}func main() {intChan := make(chan int, 10)boolChan := make(chan bool, 1) //用来标记是否执行完的管道go Read(intChan, boolChan) //开启消费者go Write(intChan)          //开启生产者for { //让主线程一直在这里等待,直到boolChan有数据了_, ok := <-boolChanif ok {break}}
}

5.4、Channel一些使用细节和注意事项

在go语言当中如果某个协程出现了异常,如果我们不做任何处理那么就会导致整个程序崩溃掉。在go语言当中我们可以使用   

     defer + recover来处理整个异常。

如果我们起了一个协程,但是这个协程出现了panic,如果我们没有捕获这个panic,就会造成整个程序崩溃,这时我们可以在goroutine中使用recover来捕获panic,进行处理,这样即使这个协程发生的问题,但是主线程仍然不受影响,可以继续执行

package mainimport ("fmt""time"
)/*go语言当中使用recover解决协程当中出现的panic导致程序崩溃的问题如果一个协程出现了异常会导致整个程序崩溃,此时我们需要使用recover来捕获这个panic这样就不会影响其它协程*/func Say() {for i := 0; i < 10; i++ {fmt.Println("hello world")}
}func Test() {//使用defer + recover捕获抛出的panicdefer func() { if err := recover(); err != nil {fmt.Println("test()协程发生错误:\n", err)}}()var myMap map[int]string //需要提前makemyMap[0] = "提升和"         //没有提前make}
func main() {go Test()go Say()time.Sleep(time.Second)
}

相关文章:

Go并发编程(上)

目录 一、go语言当中的协程 二、MPG模型介绍 三、Goroutine 的使用 3.1 协程的开启 3.2 优雅地等待子协程结束 四、捕获子协程的panic 五、管道Channel 5.1、认识管道 5.2、Channel的遍历和关闭 5.3 、用管道实现生产者消费者模型 5.4、Channel一些使用细节和注意事…...

MarkDown基础及表格、KaTeX公式、矩阵、流程图、UML图、甘特图语法

概述 最多可设置6级标题 技巧 列表 有序列表 MD语法&#xff1a; 1. 你好 2. 我也好呈现效果&#xff1a; 你好我也好 无序列表 MD语法&#xff1a; - a - b * aa * bbaaabbb效果&#xff1a; ab aabb aaabbb 结论&#xff0c;支持三种方式&#xff1a;-、*、 T…...

Citespace的使用

CiteSpace CiteSpace的相关介绍运行CiteSpace CiteSpace的相关介绍 CiteSpace作为一款优秀的文献计量学软件&#xff0c;能够将文献之间的关系以科学知识图谱的方式可视化地展现在我们面前。简单来说&#xff0c;面对海量的文献&#xff0c;CiteSpace能够迅速锁定自己需要关注…...

[模块]ES6与cjs的混合开发

[模块]ES6与cjs的混合开发 模块语言混合开发的原因Nodejs中使用ES6关于动态加载的讲解 项目的模块语言CJS 与 ESM 开发模块的使用方法普通模块引入json 文件的引入普通模块导出 CJS兼容ESMESM兼容CJS(推荐)全局变量--dirname-filename-esm库 问题Error: EPERM: operation not p…...

git上传项目至github(Linux)

01 git版本创建 git init 创建版本库 创建一个版本 git add test1.cpp git commit -m 说明信息 git log 查看版本记录 02 版本回退 git reset --hard HEAD^ 版本回退一个 git reset --hard HEAD^^ 版本回退二个 git reset --hard 版本号 版本回退到指定版本&#xff0…...

SSH 远程登录 WSL

更新ssh设置 sudo apt-get update sudo apt-get remove openssh-server sudo apt-get install openssh-server 编辑网络配置 sudo vi /etc/ssh/sshd_config &#xff08;1&#xff09;修改ssh服务监听端口和监听地址 注意&#xff1a;为了个人的安全&#xff0c;还是建议换…...

每天一道算法题:40. 组合总和 II

难度 中等 题目 给定一个候选人编号的集合 candidates 和一个目标数 target &#xff0c;找出 candidates 中所有可以使数字和为 target 的组合。 candidates 中的每个数字在每个组合中只能使用 一次 。 注意&#xff1a;解集不能包含重复的组合。 示例 1: 输入: candidat…...

Centos7安装PostgreSQL 14

环境&#xff1a; Centos7安装PostgreSQL_14版本数据库&#xff1b; 打开官方网站&#xff1a;PostgreSQL: Linux downloads (Red Hat family) 一、 版本选择 复制、粘贴并运行如下脚本&#xff1a; 二、安装步骤 这些命令是在 CentOS 7.x 系统上安装和配置 PostgreSQL 14 的步…...

Shopee的折扣活动怎么分类?shopee设置折扣注意事项

旺季到来&#xff0c;Shopee会举办一些折扣活动来吸引客户&#xff0c;那么shopee的折扣活动怎么分类&#xff0c;shopee设置折扣注意事项&#xff1f; shopee的折扣活动怎么分类&#xff1f; 满减活动&#xff1a;满减活动是虾皮常见的一种折扣形式。在这种活动中&#xff0…...

磁盘空间占用巨大的meta.db-wal文件缓存(tracker-miner-fs索引服务)彻底清除办法

磁盘命令参考本博客linux磁盘空间满了怎么办. 问题: 磁盘空间被盗 今天瞄了一下我的Ubuntu系统盘&#xff0c; nftdiggernftdigger-Ubuntu:~$ df -h 文件系统 容量 已用 可用 已用% 挂载点 udev 16G 0 16G 0% /dev tmpfs 3.2G 1.9…...

力扣:160. 相交链表(Python3)

题目&#xff1a; 给你两个单链表的头节点 headA 和 headB &#xff0c;请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点&#xff0c;返回 null 。 图示两个链表在节点 c1 开始相交&#xff1a; 题目数据 保证 整个链式结构中不存在环。 注意&#xff0c;…...

【华为OD机试AB高分必刷题目】无名的搜索题(Java-优先搜索(DFS)实现)

🚀你的旅程将在这里启航!本专栏所有题目均包含优质解题思路,高质量解题代码,详细代码讲解,助你深入学习,高分通过! 文章目录 【华为OD机试AB高分必刷题目】无名的搜索题(Java-优先搜索(DFS)实现)题目描述解题思路Java题解代码代码OJ评判结果代码讲解寄语【华为OD机…...

ant 任务(task)通过内嵌的arg元素传递命令行参数

有的ant 任务将参数传递给其它的进程作为命令行参数。这可以通过内嵌的arg元素来实现。 例如&#xff1a; <exec executable"${browser}" spawn"true"><arg value"${file}"/> </exec>arg元素的部分属性说明&#xff1a; val…...

STM32G0+EMW3080+阿里云飞燕平台实现单片机WiFi智能联网功能(三)STM32G0控制EMW3080实现IoT功能

项目描述&#xff1a;该系列记录了STM32G0EMW3080实现单片机智能联网功能项目的从零开始一步步的实现过程&#xff1b;硬件环境&#xff1a;单片机为STM32G030C8T6&#xff1b;物联网模块为EMW3080V2-P&#xff1b;网联网模块的开发板为MXKit开发套件&#xff0c;具体型号为XCH…...

IntelliJ IDEA - Git Commit 后 Commit 窗口不消失解决方案

这个现象是在 2023 年版本后开始的&#xff0c;一开始以为是 Mac 系统的原因&#xff0c;后来发现原来 Windows 也这样&#xff0c;所以应该只跟 IDEA 版本有关 可以看到左侧 commit 后&#xff0c;这个侧边栏还在&#xff0c;按理讲在以前的版本是之前消失&#xff0c;这样使…...

Vue 组件化编程 和 生命周期

目录 一、组件化编程 1.基本介绍 : 2.原理示意图 : 3.全局组件示例 : 4.局部组件示例 : 5.全局组件和局部组件的区别 : 二、生命周期 1.基本介绍 : 2.生命周期示意图 : 3.实例测试 : 一、组件化编程 1.基本介绍 : (1) 开发大型应用的时候&#xff0c;页面往往划分成…...

《数字图像处理-OpenCV/Python》连载(41)图像的旋转

《数字图像处理-OpenCV/Python》连载&#xff08;41&#xff09;图像的旋转 本书京东优惠购书链接&#xff1a;https://item.jd.com/14098452.html 本书CSDN独家连载专栏&#xff1a;https://blog.csdn.net/youcans/category_12418787.html 第 6 章 图像的几何变换 几何变换分…...

案例 - 拖拽上传文件,生成缩略图

直接看效果 实现代码 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>拖拽上传文件</title>&l…...

PHP 使用递归方式 将其二维数组整合为层级树 其中层级id 为一个uuid的格式 造成的诡异问题 已解决

不啰嗦 直接上源代码 <?php function findChildren($list, $p_id){$r array();foreach ($list as $k > $item) {if ($item[fid] $p_id) {unset($list[$k]);$length count($r);$r[$length] $item;if ($t findChildren($list, $item[id])) {$r[$length][children] …...

rv1126-rv1109-添加分区,定制固件,开机挂载功能

===================================================================== 修改分区: 这里是分区的txt文件选择; 这里是分区的划分,我这里回车了,方便看 FIRMWARE_VER: 8.1 MACHINE_MODEL: RV1126 MACHINE_ID: 007 MANUFACTURER: RV1126 MAGIC: 0x5041524B ATAG: 0x00200…...

别再只会print了!用Python tkinter给你的脚本加个可视化界面(附完整代码)

从命令行到可视化&#xff1a;用tkinter为Python脚本打造专业GUI界面 每次运行Python脚本时&#xff0c;面对黑漆漆的命令行窗口和单调的print输出&#xff0c;你是否想过给它一个更友好的面孔&#xff1f;上周我为一个数据分析脚本添加了简单GUI后&#xff0c;用户反馈直接提升…...

抖音内容高效下载与管理:douyin-downloader 实用指南

抖音内容高效下载与管理&#xff1a;douyin-downloader 实用指南 【免费下载链接】douyin-downloader A practical Douyin downloader for both single-item and profile batch downloads, with progress display, retries, SQLite deduplication, and browser fallback suppor…...

Python爬虫实战:手把手教你智慧场馆工程 - 构建全球会展功能分区结构化词表!

㊗️本期内容已收录至专栏《Python爬虫实战》&#xff0c;持续完善知识体系与项目实战&#xff0c;建议先订阅收藏&#xff0c;后续查阅更方便&#xff5e; ㊙️本期爬虫难度指数&#xff1a;⭐ (基础入门篇) &#x1f250;福利&#xff1a; 一次订阅后&#xff0c;专栏内的所有…...

Windows右键菜单终极优化指南:如何用ContextMenuManager打造高效操作环境

Windows右键菜单终极优化指南&#xff1a;如何用ContextMenuManager打造高效操作环境 【免费下载链接】ContextMenuManager &#x1f5b1;️ 纯粹的Windows右键菜单管理程序 项目地址: https://gitcode.com/gh_mirrors/co/ContextMenuManager 你是否经常在Windows右键菜…...

从零到一:3天用Unity和WPF打造专属Galgame播放器《Galplayer》实战手记

从零到一&#xff1a;3天用Unity和WPF打造专属Galgame播放器《Galplayer》实战手记 当你想在手机上流畅体验Galgame剧情&#xff0c;却发现现有播放器要么功能简陋&#xff0c;要么操作繁琐时&#xff0c;有没有想过自己动手打造一个专属播放器&#xff1f;本文将带你完整复盘…...

空间注意力机制(SAM)的实证研究:超越Transformer的设计启示

1. 空间注意力机制&#xff08;SAM&#xff09;的前世今生 第一次接触空间注意力机制是在2019年那篇微软亚研的论文里&#xff0c;当时就被它反直觉的结论震撼到了。你可能听说过Transformer&#xff0c;但SAM才是真正让我重新思考注意力机制本质的研究。简单来说&#xff0c;它…...

Java 高并发场景下 Redis 分布式锁(UUID+Lua)最佳实践

一、核心原理&#xff1a;Redis 分布式锁的设计基石1.1 分布式锁的核心要求一款可靠的分布式锁需满足以下 4 点核心要求&#xff0c;否则易引发死锁、锁误删、数据不一致等问题&#xff1a;互斥性&#xff1a;同一时间只有一个线程能持有锁&#xff0c;杜绝并发竞争&#xff1b…...

AbMole 丨 FIN56 通过降解 GPX4 与调控 CoQ10 诱导铁死亡

FIN56&#xff08;AbMole&#xff0c;M6731&#xff09;是一种铁死亡&#xff08;ferroptosis&#xff09;诱导剂[1]&#xff0c;其作用机理具有双重性&#xff1a;一方面&#xff0c;FIN56通过诱导谷胱甘肽过氧化物酶4&#xff08;GPX4&#xff09;蛋白的降解来触发铁死亡&…...

SAP ECC6 EC-CS 合并报表操作手册(完整版)

SAP ECC6 EC-CS 合并报表操作手册&#xff08;完整版&#xff09;适用版本&#xff1a;ECC6.0&#xff08;含 EHP&#xff09;模块&#xff1a;EC-CS&#xff08;Enterprise Controlling – Consolidation&#xff09;核心用途&#xff1a;法定合并、管理合并、内部交易抵销、股…...

Elasticsearch性能调优:深入解析Segment合并策略与实战配置

1. 为什么Segment合并是Elasticsearch性能的关键 第一次接触Elasticsearch时&#xff0c;我被它惊人的搜索速度震撼了。直到有一天&#xff0c;我们的日志系统突然变慢&#xff0c;查询响应从毫秒级跌到秒级&#xff0c;我才真正开始关注背后的Segment机制。想象一下&#xff0…...