为什么你的程序跑不满CPU?——简单聊聊多核多线程

news2024/11/25 14:59:00

最近同事测试自己的程序,感觉处理耗时太长,一看CPU使用率,才25%。想要提高CPU使用率降低处理时长,于是向我询问。以此为契机写了这篇,聊聊多核多线程。水平有限,仅供参考。

1.单核单线程

一切开始的前提是,你需要知道,CPU执行的所有代码其实就是一条条指令。

首先来聊聊单核单线程下你的程序是怎么运行的。假如你的程序就两行代码:

b=a+1;

c=b+1;

而你的CPU每运行一行代码需要1秒,那么很明显,对于单核CPU来说,运行你的代码需要2秒。但实际上这往往需要2秒多,因为你的CPU还需要处理很多可能的中断,比如当你的CPU刚执行完b=a+1时, 这个时候插入了一台USB设备,它触发了一个中断,中断你可以简单理解为一个函数,这里的USB中断你可以理解为,插入了USB就要执行一个“USB函数”,这个过程不受控制(实际过程复杂的多)。一般来说中断优先级是高于你的用户代码的,所以CPU只能转头去执行USB函数中的代码,这个时候你的代码才执行到了一半,当执行完USB函数后,CPU才会转头回来继续执行你的代码。最终你的代码可能运行了3秒甚至更久。

2.单核多线程

你可能觉得2秒甚至更久的时间对你的程序来说太长了,那是否可以使用多线程优化程序的执行?

其实仔细想一下就知道,无论使用多少个线程,假如CPU每执行一行代码就是1秒,那这两行代码怎么也得要2秒。所以单核情况下,多线程并不会提高代码执行效率。

单核情况下的多线程叫做并发。也就是所谓的单核多线程其实只是在同一个CPU上交替执行多个线程,但实际是,在任意时间点,只能有一个线程执行,只不过CPU切换的速度很快,给你造成一种多个线程同时运行的假象。只有多核才能做到真正意义上的同时运行。更多细节可以搜索并发并行的区别。

3.多核单线程

假如你有一个四核CPU,每个核还是1秒执行1行代码,而你的代码是:

b=a+1;

c=b+1;

e=d+1;

f=e+1;

如果把这四行代码放在一个mian函数里执行,你会发现CPU在程序执行的时候,只有25%。这是否是因为有3个核压根就没有工作?

其实不然,这种情况下,无论是只使用1个核还是四个核都使用,CPU使用率最多都是25%。为什么?

假如你的程序只放在第一个核上运行,这很好理解:

表1
时间CPU0使用率CPU1使用率CPU2使用率CPU3使用率
第1秒100%0%0%0%
第2秒100%0%0%0%
第3秒100%0%0%0%
第4秒100%0%0%0%

4秒内,CPU实际可以执行16行代码,而实际只有CPU0执行了4行,所以CPU在4秒内总的使用率为4/16=25%。

假如你的程序在4个核上运行,则可能是:

表2
时间CPU0使用率CPU1使用率CPU2使用率CPU3使用率
第1秒100%0%0%0%
第2秒0%100%0%0%
第3秒0%0%100%0%
第4秒0%0%0%100%

同样的也是25%。你可以能会好奇为何CPU不是按下面的方式运行的:

表3
时间CPU0使用率CPU1使用率CPU2使用率CPU3使用率
第1秒100%100%100%100%
第2秒0%0%0%0%
第3秒0%0%0%0%
第4秒0%0%0%0%

在这种情况下,我们统计CPU占用率的周期很重要,如果以4秒为一个周期,那CPU使用率还是25%,如果以1秒为周期则第一秒使用率是100%,后面3秒使用率都是0%。但我们最关心的还是这种情况下可以把程序执行需要4秒给缩短到1秒。但这种情况是不可能发生的,当你使用单线程写了一个程序时,就注定了你的每行代码都要依次执行(这里不考虑CPU乱序执行,且就算乱序也不影响),你的第二行代码就必须等第一行代码执行完毕才能执行,无论第一行代码或是第二行代码在哪个CPU上执行!所以,无论以哪种情况来说,你的CPU从你的代码开始到结束,占用率最多25%,且必须耗时4秒甚至更久才能执行完。

4.多核多线程

按照上面的说法,我们是否可以把4行代码分别放在四个线程中,这样岂不是可以实现表3?

实际是可以实现的,但可惜的是,计算结果是错误的。因为我们可以看到,4行代码里面,数据是有依赖关系的,计算c之前需要保证先计算b,计算b之前,需要保证a是正确的。这就是所谓的线程间同步。所以即使是使用4个线程,为了使计算结果正确,我们也没有办法做到耗时1秒。

在这个例子中,假如我们把四行代码分别放在四个线程中,然后四个线程分别在4个核上运行,比如第一个核上运行线程1,执行的是第一行代码,以此类推。

那我们的代码在实际考虑数据依赖关系后,很可能是:

第一秒,线程1执行,其他线程都等待,也就是虽然其他线程放在其他核上,但是其他核使用率仍然为0%。

第二秒,线程1执行完毕,告诉了线程2,然后线程2开始执行,此时CPU0、2、3核都没在使用。

第三秒,线程2执行完毕,告诉了线程3,然后线程3开始执行,此时CPU0、1、3核都没在使用。

第四秒,线程3执行完毕,告诉了线程4,然后线程4开始执行,此时CPU0、1、2核都没在使用。

其中一个线程如何告诉另一个线程可以搜索线程(进程)间同步方式相关资料。

我们看下来,发现好像使用多线程也并没有缩小耗时,也就是说,如果你的程序执行有数据依赖关系的,多线程并不能优化执行效率,因为你后面的代码即使可以执行,也无法执行,因为它要等待前面的代码计算完成,用前面的计算结果继续计算。

细心的你可能发现,上面例子中第三行代码并不需要等待第二行代码执行完毕,因为c=b+1和e=d+1并没有关系,也就是第二行代码必须等第一行计算完毕,第四行代码必须等第三行计算完毕,但是前两行和后两行并没有一点关系,那我们完全可以把第1、2行代码放在线程1中,运行在其中一个核上,把第3、4行代码放在线程2中,运行在另一个核上,最终CPU使用率是:

表4
时间CPU0使用率CPU1使用率CPU2使用率CPU3使用率
第1秒100%100%0%0%
第2秒100%100%0%0%
第3秒0%0%0%0%
第4秒0%0%0%0%

之前的多核单线程中,程序需要运行4秒,总体CPU使用率25%,现在程序只需要运行2秒,总体CPU使用率50%。此时才把多核多线程优势完全发挥出来。

这是否就是多线程优化极限了?

其实在特殊情况下,还可以再次优化。

多级流水线

很多情况下,我们的程序需要处理的数据是流式的,比如音视频,也就是数据会每隔一定时间来一帧,而我们的程序需要每来一帧处理一次,这个时候如果数据来的时间大于数据处理的时间,我们可以仿照CPU的多级流水线的设计思路优化我们的处理。 

按照我们上文的例子,假如我们的处理流程是这样的:

在这里,a和d每隔2秒来一次的话是可以正常输出c和f的值的,如果a和d每隔1秒来一次的话,等到下一次数据来,我们上次数据还没有计算完成,肯定会卡顿,导致数据丢失,而且这种情况无法通过缓存输入数据解决,因为这会越堆积越多。但是如果我们按照下面的思路修改:

程序运行流程是这样的:

第一秒:第一帧数据到来,线程1和线程3执行,因为没有线程1和3的结果,线程2和线程4运行跳过,最终没有输出c、f,CPU使用率50% 

第二秒:第二帧数据到来,线程1和线程3计算第二次来的数据,线程2和线程4计算上一轮中线程1和线程3输出的数据,最终输出第一帧数据对应的c、f,CPU使用率100%

第三秒:第三帧数据到来,线程1和线程3计算第三次来的数据,线程2和线程4计算上一轮中线程1和线程3输出的数据,最终输出第二帧数据对应的c、f,CPU使用率100%

余下同理。

由上可以看出,通过错位一帧,我们可以把CPU使用率从原来的50%提高到100%,虽然输出落后输入一帧,但是却可以满足1秒输出一次的要求。

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

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

相关文章

CCProxy + Proxifier 通过另一台电脑访问网络

问题场景描述: 公司提供的 vpn 只提供了 windows 客户端;Mac没有客户端,而家里的 windows 电脑是多年前的旧电脑,配置不足,所以不能使用;这里整理了一种 搭建跳板机 作为中专的方式进行访问 搭建过程 1.…

OpenCV(7)-OpenCV中的滤波器

OpenCV中的滤波器 图像滤波 滤波的作用:一幅图像通过滤波器得到另一幅图像;其中滤波器又称为卷积核,滤波的过程被称为卷积 卷积的几个基本概念: 卷积核的大小: 卷积核一般为奇数,如3 * 3,5 * 5&#xf…

【DELM回归预测】基于matlab灰狼算法改进深度学习极限学习机GWO-DELM数据回归预测【含Matlab源码 1867期】

⛄一、基本极限学习机算法简介 1 核极限学习机 极限学习机(ELM)是一种含L个神经元的单隐藏层前馈神经网络(SLFN)算法,相比于其他神经网络(如BP)具有训练速度快和泛化能力强等特点。但是ELM算法是随机生成各个神经元连接权值和阈值,易造成算法的波动性和…

架构师必读 —— 逻辑模型(4)

解决问题的基本步骤 如果情绪急躁,过于钻牛角尖,坚持“这就是唯一结论”的态度,就会阻碍逻辑思考。情绪急躁、钻牛角尖的行为属短见薄识,只能导致主观臆断。一味地想“简短地传达观点”时,往往会跳过三角逻辑中的论据和…

VSCode下载和安装详细步骤

一、下载 点击 这里 到Visual Studio Code官网下载。 选择下载版本,大家按自己的电脑版本进行选择(这里我选的是Windows 64位的)。 二、安装 1. 下载好之后,双击进行安装; 2. 选择【我同意此协议】,再点…

如何快速上手react中的redux管理库

前言: 什么是redux?redux和vuex一样,都被统称为状态管理库,是核心数据存贮与分发、监听数据改变的核心所在。 可以简单说下redux和vuex的区别: 相同点 state 共享数据流程一致:定义全局state,…

【DELM回归预测】基于matlab粒子群算法改进深度学习极限学习机PSO-DELM数据回归预测【含Matlab源码 1884期】

⛄一、PSO-DELM简介 1 DELM的原理 在2004年,极限学习机(extreme learning machine,ELM)理论被南洋理工大学的黄广斌教授提出,ELM是一种单隐含层前馈神经网络(single-hidden layer feedforward neural network,SLFN&am…

静态HTML个人音乐网页 大学生网页设计作业 简单音乐娱乐网页制作 DW个人网站模板下载 大学生简单音乐网页作品代码

🎉精彩专栏推荐 💭文末获取联系 ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 💂 作者主页: 【主页——🚀获取更多优质源码】 🎓 web前端期末大作业: 【📚毕设项目精品实战案例 (10…

基于风驱动算法改进的DELM预测-附代码

风驱动算法改进的深度极限学习机DELM的回归预测 文章目录风驱动算法改进的深度极限学习机DELM的回归预测1.ELM原理2.深度极限学习机(DELM)原理3.风驱动算法4.风驱动算法改进DELM5.实验结果6.参考文献7.Matlab代码1.ELM原理 ELM基础原理请参考&#xff1…

12月编程语言排行榜,java跌至低点,低代码发展迅猛

2022年12月编程语言排行榜:TIOBE Index for December 2022 TIOBE揭晓了12月全球编程语言排名,Python 以0.1%微弱优势领先C语言,成功夺冠。目前,这两种语言竞争焦灼,都是多次霸榜。 本次榜单,C作为一匹黑马…

chrome插件开发之发送网络请求v3版本

如果某个扩展希望访问自己所属域以外的资源,比如说来自http://www.google.com的资源(假设该扩展不是来自www.google.com), 浏览器不会允许这样的请求,除非该扩展获得了相应的跨域请求允许。 获取跨域请求允许 通过添加域名或者域名匹配到manifest文件的p…

CentOS 8:Redis服务器

Redis ,一款基于内存的键值型数据库服务器 常见于网站开发场景 Redis 服务器只发布了 Linux 版本 Redis服务器的安装,有3种办法: 1 自动安装 , redis 5.0 yum install redis 2 源码方式 从官网下载源码,先编译、后部署 3 …

WhaleDI数据治理利器之“低成本数据质量管理”

数字化时代,数据已经成为企业管理的关键要素,随着数据的日益增长及汇聚,企业数据质量问题成为数据治理的关键。数据质量直接影响到能否通过数据分析驱动企业生产、运营、服务提效及创新。高质量的数据对管理决策、业务支撑等都有极其重要的作…

时间序列的研究

更多的时间预测,参考 https://github.com/qingsongedu/awesome-AI-for-time-series-papers#AI4TS-Tutorials 1. 周期检测模块 可能存在的情况, 单周期多周期无周期; Robust Period 检测 该时间序列,是否有周期 以及周期的长度…

C语言浮点型的存储

3.14159 1e10可以写成1.010的10次方 1e5 表示 1.010的5次方 int main() {int n 9;//4bytefloat* pFloat (float*)&n;//float 指针访问4的字节printf("n值为:%d", n);//9printf("*pFloat值为:%f\n", *pFloat);//,是以浮点数的视角去看的*p…

深度学习基础知识---梯度弥散 梯度爆炸

目录 1 梯度弥散、梯度爆炸的成因 2 解决方式 2.1.pretrainfinetune 2.2 梯度裁剪 2.3 权重正则化 2.5 Batch Normalization正则化 2.6 残差结构 shortcut 2.7 LSTM 1 梯度弥散、梯度爆炸的成因 神经网络的层(主要是隐藏层)越多,对…

【LSTM时序预测】基于matlab EMD结合LSTM风速数据预测【含Matlab源码 2051期】

⛄一、EMD-DELM简介 1 方法及原理 1.1 EMD基本原理 经验模态分解可基于数据本身,将复杂信号分解为一系列IMF和一个r(t),分解信号时,不需要预先设置任何基函数。因为这一特点,理论上EMD方法可预处理任何一种信号的数据,因此被广泛…

【Linux磁盘管理】

Linux磁盘管理 写在前面 在此强调一个 Linux 的核心机制就是一切皆文件。 I/O Ports 即I/O 设备地址,用来标识硬件对应的设备地址,来让操作系统以及 cpu 使用。 CPU 的核数不一定就是越多越好,由于CPU 协调之间的协调问题,可能性…

洛谷P1161 开灯

开灯 题目描述 在一条无限长的路上,有一排无限长的路灯,编号为 1,2,3,4,…1,2,3,4,\dots1,2,3,4,…。 每一盏灯只有两种可能的状态,开或者关。如果按一下某一盏灯的开关,那么这盏灯的状态将发生改变。如果原来是开,…

定时器/计数器中定时/计数初值的计算

寄存器TMOD是单片机的一个特殊功能寄存器,其功能是控制定时器/计数器T0、T1的工作方式。它的字节地址为89H,不可以对它进行位操作。 只能进行字节操作,即给寄存器整体赋值的方法设置初始值,如TMOD0x01。在上电和复位时&#xff0c…