【Go】十七、进程、线程、协程
文章目录
- 1、进程、线程
- 2、协程
- 3、主死从随
- 4、启动多个协程
- 5、使用WaitGroup控制协程退出
- 6、多协程操作同一个数据
- 7、互斥锁
- 8、读写锁
- 9、defer+recover优化多协程
1、进程、线程
- 进程作为资源分配的单位,在内存中会为每个进程分配不同的内存区域
- 一个进程下面有多个线程,干着不同的活儿
进程与线程,好比打开360,同时进行木马查杀和电脑清理,360是一个进程,后面两个则是两个线程
补充,关于并行和并发:
- 并发:多线程同时/交替操作同一资源类
- 并行:多线程同时操作多个资源类
示意图:
2、协程
- 协程是一种用户态的轻量级线程
- 又称微线程、纤程
- 是一种单线程下的并发
- 协程中只有一个线程在执行(协程的本质是个单线程)
在一个单独的线程中,出现IO操作时,此时可控制单线程下的多个任务,在另一个任务IO阻塞时,将其寄存器上下文和栈保存到某个地方,去切到另一个任务继续计算。如此,就保证了线程最大程度的处于就绪状态,执行效率变高。
协程的引入,给CPU一种:该线程好像是一直在计算,io比较少的错觉,从而会更多的将cpu的执行权限分配给我们的线程
线程是CPU控制的,而协程是程序自身控制的,属于程序级别的切换,操作系统完全感知不到,因而更加轻量级
感觉在线程的基础上再细分,还是因为后面计算机在硬件上发展快了,如此再做切换,可以更加提升效率。
package main
import("fmt""strconv""time"
)
func test(){for i := 1;i <= 10;i++ {fmt.Println("hello golang + " + strconv.Itoa(i))//阻塞一秒:time.Sleep(time.Second)}
}
func main(){//主线程go test() //开启一个协程for i := 1;i <= 10;i++ {fmt.Println("hello 9527 + " + strconv.Itoa(i))//阻塞一秒:time.Sleep(time.Second)}
}
如上,主线程中,开启一个协程,协程每1秒输出hello golang,主线程每一秒输出一次hello 9527,主线程和协程在同时执行,且属于同一个线程(主线程)。运行:
3、主死从随
即:
- 主线程执行结束退出了,则即使其下的协程没有执行完,也要跟着陪葬
- 当然协程如果提前在主线程之前结束,那就正常自己结束就好
package main
import("fmt""strconv""time"
)
func test(){for i := 1;i <= 1000;i++ {fmt.Println("hello golang + " + strconv.Itoa(i))//阻塞一秒:time.Sleep(time.Second * 1)}
}
func main(){//主线程go test() //开启一个协程for i := 1;i <= 10;i++ {fmt.Println("hello msb + " + strconv.Itoa(i))//阻塞一秒:time.Sleep(time.Second * 1)}
}
4、启动多个协程
package main
import("fmt""time"
)
func main(){//匿名函数+外部变量 = 闭包for i := 1;i <= 5;i++ {//启动一个协程//使用匿名函数,直接调用匿名函数go func(n int){fmt.Println(n)}(i)}time.Sleep(time.Second * 2)
}
5、使用WaitGroup控制协程退出
思想类似Java的计数器那些JUC辅助类,用来解决主线程在子协程结束后自动结束,即阻塞线程,等等所有协程执行完。核心方法:
//协程开始的时候加1操作
func (wg*WaitGroup) Add(delta int)//协程执行完后减一
func(wg *WaitGroup) Done()//WaitGroup为0前,阻塞线程
func(wg *WaitGroup) Wait()
示例:
package main
import("fmt""sync"
)
var wg sync.WaitGroup //只定义无需赋值
func main(){//启动五个协程for i := 1 ;i <= 5;i++ {wg.Add(1) //协程开始的时候加1操作go func(n int){fmt.Println(n)wg.Done() //协程执行完成减1}(i)}//主线程一直在阻塞,什么时候wg减为0了,就停止wg.Wait()
}
当然也可用defer关键字去减一
package main
import("fmt""sync"
)
var wg sync.WaitGroup
func main(){for i := 1 ;i <= 5;i++ {wg.Add(1) go func(n int){defer wg.Done() //!!!这里fmt.Println(n) }(i)}wg.Wait()
}
可以最开始在知道协程次数的情况下先Add操作
package main
import("fmt""sync"
)
var wg sync.WaitGroup
func main(){wg.Add(5) //这里!!!for i := 1 ;i <= 5;i++ {go func(n int){defer wg.Done()fmt.Println(n) }(i)}wg.Wait()
}
注意Add的个数和协程的个数要一致。
6、多协程操作同一个数据
开一个协程去做一万次+1,再开一个协程去做一万次-1
package main
import("fmt""sync"
)
//定义一个变量:
var totalNum int
var wg sync.WaitGroup //只定义无需赋值
func add(){defer wg.Done()for i := 0 ;i < 100000;i++{totalNum = totalNum + 1}
}func sub(){defer wg.Done()for i := 0 ;i < 100000;i++{totalNum = totalNum - 1}
}func main(){wg.Add(2)//启动协程go add()go sub()wg.Wait()fmt.Println(totalNum)
}
运行的结果始终不为0:
多协程操作同一个数据的问题:按以下1.2.3.4.5.6的步骤,就发现做了一次+1,一次-1,结果为-1
修复这个问题,让一个协程执行逻辑的时候,另一个协程不执行 ⇒ 互斥锁
7、互斥锁
引入sync包:
//加入互斥锁:
var lock sync.Mutex
package main
import("fmt""sync"
)
//定义一个变量:
var totalNum int
var wg sync.WaitGroup //只定义无需赋值
//加入互斥锁:
var lock sync.Mutex
func add(){defer wg.Done()for i := 0 ;i < 100000;i++{//加锁lock.Lock()totalNum = totalNum + 1//解锁:lock.Unlock()}
}
func sub(){defer wg.Done()for i := 0 ;i < 100000;i++{//加锁lock.Lock()totalNum = totalNum - 1//解锁:lock.Unlock()}
}
func main(){wg.Add(2)//启动协程go add()go sub()wg.Wait()fmt.Println(totalNum)
}
8、读写锁
互斥锁在读多写少的场景不适合,性能低下,采用读写互斥,但读读共享的读写锁。
//加入读写锁:
var lock sync.RWMutex
lock.RLock()//读锁
lock.RUnlock()
示例:
package main
import("fmt""sync""time"
)
var wg sync.WaitGroup //只定义无需赋值
//加入读写锁:
var lock sync.RWMutex
func read(){defer wg.Done()lock.RLock()//如果只是读数据,那么这个锁不产生影响,但是读写同时发生的时候,就会有影响fmt.Println("开始读取数据")time.Sleep(time.Second)fmt.Println("读取数据成功")lock.RUnlock()
}
func write(){defer wg.Done()lock.Lock()fmt.Println("开始修改数据")time.Sleep(time.Second * 10)fmt.Println("修改数据成功")lock.Unlock()
}
func main(){wg.Add(6)//启动协程 ---> 场合:读多写少for i := 0;i < 5;i++ {go read()}go write()wg.Wait()
}
运行发现:写的时候不能读,但读的时候可以共享读:
9、defer+recover优化多协程
多协程工作,一个协程出现panic,整个程序崩溃。引入defer+recover,让协程即使出现错误,也不影响主线程和其他协程的执行:
ackage main
import("fmt""time"
)
//输出数字:
func printNum(){for i := 1;i <= 10;i++{fmt.Println(i)}
}
//做除法操作:
func devide(){defer func(){err := recover()if err != nil{fmt.Println("devide()出现错误:",err)}}()num1 := 10num2 := 0result := num1 / num2fmt.Println(result)
}
func main(){//启动两个协程:go printNum()go devide()time.Sleep(time.Second * 5)
}
运行:
相关文章:

【Go】十七、进程、线程、协程
文章目录 1、进程、线程2、协程3、主死从随4、启动多个协程5、使用WaitGroup控制协程退出6、多协程操作同一个数据7、互斥锁8、读写锁9、deferrecover优化多协程 1、进程、线程 进程作为资源分配的单位,在内存中会为每个进程分配不同的内存区域 一个进程下面有多个…...
深入剖析JavaScript中的this(上)
在Javascript中,this 关键字是一个非常重要的概念,this这个关键字可以说是很常见也用的很多,说它简单也很简单,说它难也很难。我们经常会用到this,也经常会因为this头疼,是一个经常被误解和误用的概念&…...

Junit深入讲解(JAVA单元测试框架)
1、此处用的是Junit5,此处pom文件需要引的依赖是 <dependency><groupId>org.junit.jupiter</groupId><artifactId>junit-jupiter-api</artifactId><version>5.9.1</version><scope>test</scope></depende…...

Spring boot如何执行单元测试?
Spring Boot 提供了丰富的测试功能,主要由以下两个模块组成: spring-boot-test:提供测试核心功能。spring-boot-test-autoconfigure:提供对测试的自动配置。 Spring Boot 提供了一个 spring-boot-starter-test一站式启动器&…...

Django详细教程(一) - 基本操作
文章目录 前言一、安装Django二、创建项目1.终端创建项目2.Pycharm创建项目(专业版才可以)3.默认文件介绍 三、创建app1.app介绍2.默认文件介绍 四、快速上手1.写一个网页步骤1:注册app 【settings.py】步骤2:编写URL和视图函数对…...

Qt编译QScintilla(C++版)过程记录,报错-lqscintilla2_qt5d、libqscintilla2_qt5找不到问题解决
Qt编译QScintilla [C版] 过程记录 本文是编译该 QScintilla 组件库供 QtCreater 开发 C 桌面软件 流程记录一、编译环境 系统: Windows 10Qt:Qt 5.14.2编译套件:MinGW 64Qscintilla:QScintilla_src-2.11.6 二、下载链接 网站链…...
android QtScrcpy 共享屏幕 获取本地Address
android QtScrcpy https://gitee.com/B arryda/QtScrcpy scrcpy - 手机无线投屏到电脑 https://zhuanlan.zhihu.com/p/80264357?utm_sourcewechat_session public String getLocalIpAddress() { String ipv4; List<NetworkInterface> nilist …...

【SQL Server】1. 认识+使用
1. 创建数据库的默认存储路径 C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Microsoft SQL Server 2008 R2 当我们选择删除数据库时,对应路径下的文件也就删除了 2. 导入导出数据工具的路径 3. 注册数据库遇到的问题 ??? 目前的问题就是服务器新建…...

视频汇聚/安防监控/视频存储EasyCVR平台EasyPlayer播放器更新:新增【性能面板】
视频汇聚/安防监控/视频存储平台EasyCVR基于云边端架构,可以在复杂的网络环境中快速、灵活部署,平台视频能力丰富,可以提供实时远程视频监控、视频录像、录像回放与存储、告警、语音对讲、云台控制、平台级联、磁盘阵列存储、视频集中存储、云…...

图神经网络实战(7)——图卷积网络(Graph Convolutional Network, GCN)详解与实现
图神经网络实战(7)——图卷积网络详解与实现 0. 前言1. 图卷积层2. 比较 GCN 和 GNN2.1 数据集分析2.2 实现 GCN 架构 小结系列链接 0. 前言 图卷积网络 (Graph Convolutional Network, GCN) 架构由 Kipf 和 Welling 于 2017 年提出,其理念是…...

大话设计模式之外观模式
外观模式(Facade Pattern)是一种软件设计模式,旨在提供一个简单的接口,隐藏系统复杂性,使得客户端能够更容易地使用系统。这种模式属于结构型模式,它通过为多个子系统提供一个统一的接口,简化了…...

CAD Plant3D 2024 下载地址及安装教程
CAD Plant3D是一款专业的三维工厂设计软件,用于在工业设备和管道设计领域进行建模和绘图。它是Autodesk公司旗下的AutoCAD系列产品之一,专门针对工艺、石油、化工、电力等行业的设计和工程项目。 CAD Plant3D提供了一套丰富的工具和功能,帮助…...

Intellij IDEA / Android studio 可持续开发笔记
Intellij 的Java/安卓工具链有着一种不可持续性,这种不可持续性体现在多个方面。 首先是不可持续运行。IDEA 使用时间越长,内存占用越大,从不主动释放。运行时间越长,日志越多,从不主动清理。 然后是不完整的开源&am…...

c++----list模拟实现
目录 1. list的基本介绍 2. list的基本使用 2.1 list的构造 用法示例 2.2 list迭代器 用法示例 2.3. list容量(capacity)与访问(access) 用法示例 2.4 list modifiers 用法示例 2.5 list的迭代器失效 3.list的模拟实现 3.1…...
FastAPI+React全栈开发15 让我们构建一个展示API
Chapter03 Getting Started with FastAPI 15 Let’s Build a showcase API FastAPIReact全栈开发15 让我们构建一个展示API REST APIs are all about cycles of HTTP requests and responses, it is the engine that powers the web and is implemented in every web framew…...
list(链表)容器(二)
一、list 插入和删除 函数原型: push_back(elem);//在容器尾部加入一个元素 pop_back();//删除容器中最后一个元素 push_front(elem);//在容器开头插入一个元素 pop_front();//从容器开头移除第一个元素 insert(pos,elem);//在pos位置插elem元素的拷贝,…...

世优科技上榜2024年度《中国虚拟数字人影响力指数报告》
日前,第三期《中国虚拟数字人影响力指数报告》在中国网络视听大会上正式发布。本期《报告》由中国传媒大学媒体融合与传播国家重点实验室(以下简称“国重实验室”)、中国传媒大学数字人研究院编制,中国网络视听协会、人民日报智慧…...
【调试方法】C代码中dump中间数据的方法
一,简介 本文主要介绍,如何在C语言代码中将音频流数据进行写入文件,方便调试定位问题: 二,函数实现 按int8_t写入 #include <stdio.h>int32_t write_int8_t_data(int8_t *name, int8_t *buffer, int32_t dat…...
【BUG】vue中@change时间传值丢失问题
项目场景: 在修改项目bug时,发现后端响应到前端的值,通过change事件调用方法,在方法中拿到值时,有部分数据丢失。 问题描述 后端传到前端的值为:字符串类型的"00000089",change调用…...

Linux提权!!!
上一篇文章讲了Windows的提权,那么这篇文章就来讲一下Linux的提权 1.SUID提权 suid权限 作用:让普通用户临时拥有该文件的属主的执行权限,suid权限只能应用在二进制可执行文件(命令)上,而且suid权限只能设置…...

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明
LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造,完美适配AGV和无人叉车。同时,集成以太网与语音合成技术,为各类高级系统(如MES、调度系统、库位管理、立库等)提供高效便捷的语音交互体验。 L…...

Chapter03-Authentication vulnerabilities
文章目录 1. 身份验证简介1.1 What is authentication1.2 difference between authentication and authorization1.3 身份验证机制失效的原因1.4 身份验证机制失效的影响 2. 基于登录功能的漏洞2.1 密码爆破2.2 用户名枚举2.3 有缺陷的暴力破解防护2.3.1 如果用户登录尝试失败次…...

相机Camera日志实例分析之二:相机Camx【专业模式开启直方图拍照】单帧流程日志详解
【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了: 这一篇我们开始讲: 目录 一、场景操作步骤 二、日志基础关键字分级如下 三、场景日志如下: 一、场景操作步骤 操作步…...

如何将联系人从 iPhone 转移到 Android
从 iPhone 换到 Android 手机时,你可能需要保留重要的数据,例如通讯录。好在,将通讯录从 iPhone 转移到 Android 手机非常简单,你可以从本文中学习 6 种可靠的方法,确保随时保持连接,不错过任何信息。 第 1…...

涂鸦T5AI手搓语音、emoji、otto机器人从入门到实战
“🤖手搓TuyaAI语音指令 😍秒变表情包大师,让萌系Otto机器人🔥玩出智能新花样!开整!” 🤖 Otto机器人 → 直接点明主体 手搓TuyaAI语音 → 强调 自主编程/自定义 语音控制(TuyaAI…...
工业自动化时代的精准装配革新:迁移科技3D视觉系统如何重塑机器人定位装配
AI3D视觉的工业赋能者 迁移科技成立于2017年,作为行业领先的3D工业相机及视觉系统供应商,累计完成数亿元融资。其核心技术覆盖硬件设计、算法优化及软件集成,通过稳定、易用、高回报的AI3D视觉系统,为汽车、新能源、金属制造等行…...

VM虚拟机网络配置(ubuntu24桥接模式):配置静态IP
编辑-虚拟网络编辑器-更改设置 选择桥接模式,然后找到相应的网卡(可以查看自己本机的网络连接) windows连接的网络点击查看属性 编辑虚拟机设置更改网络配置,选择刚才配置的桥接模式 静态ip设置: 我用的ubuntu24桌…...

深度学习水论文:mamba+图像增强
🧀当前视觉领域对高效长序列建模需求激增,对Mamba图像增强这方向的研究自然也逐渐火热。原因在于其高效长程建模,以及动态计算优势,在图像质量提升和细节恢复方面有难以替代的作用。 🧀因此短时间内,就有不…...

基于PHP的连锁酒店管理系统
有需要请加文章底部Q哦 可远程调试 基于PHP的连锁酒店管理系统 一 介绍 连锁酒店管理系统基于原生PHP开发,数据库mysql,前端bootstrap。系统角色分为用户和管理员。 技术栈 phpmysqlbootstrapphpstudyvscode 二 功能 用户 1 注册/登录/注销 2 个人中…...
comfyui 工作流中 图生视频 如何增加视频的长度到5秒
comfyUI 工作流怎么可以生成更长的视频。除了硬件显存要求之外还有别的方法吗? 在ComfyUI中实现图生视频并延长到5秒,需要结合多个扩展和技巧。以下是完整解决方案: 核心工作流配置(24fps下5秒120帧) #mermaid-svg-yP…...