如何提高多线程程序的cpu利用率
正如大家所知道的那样,多核多cpu越来越普遍了,而且编写多线程程序也是件很简单的事情。在Windows下面,调用CreateThread函数一次就能够以你想要的函数地址新建一个子线程运行。然后,事情确实你发现创建多线程根本没有让程序快多少,也没有提高多少cpu利用率,甚至可能让cpu利用率下降。唯一能够确定的是多线程能够避免界面假死。为什么会是这样的了。本文将举一些例子和讲述一些原因。
首先,我来讲一下多处理的一些知识。如下图所示,
多处理器系统也只有一个待运行的线程队列,内存中也只有一个操作系统拷贝,而且也只有一个内存系统,但是会有多个cpu同时运行不同的线程。一个cpu运行一个线程,那么上图中的系统最多能在同一时间运行2个线程。其实,多处理系统需要掌握的知识不是这些,而是缓存一致性。
现在来解释下什么是缓存一致性。由于,还是只有一个内存系统。所有cpu都要和这个内存系统通信,但是只有一条总线,那么这无疑会造成总线紧张,限制整体的速度了。那么,你多个cpu也没多少意义了。解决这个问题的办法还是利用cpu的缓存机制,学过组成原理的同学都知道,cpu的缓存命中率还是很高的,有90%以上吧。那么,我继续利用缓存机制还是可以降低总线的频繁使用的。但是,每个cpu都有自己的缓存。如果有2个cpu的缓存存储的是同一内存数据的内容,其中一个cpu的缓存更新了,另外一个cpu的缓存也必须更新,这就是所谓的缓存一致性。编程多线程程序的一个很重要的一点就是避免因为缓存一致性引起的缓存更新风暴。
现在我举一个缓存更新风暴的例子。
如图所示的类定义,
锁lockHttp和lockSsl中间只有8个字节,而绝大部分系统上一个缓存行是128个字节,那么这2个锁很可能就处在同一个缓存行上面。那么,最坏的情况会发生什么事情了。假设处理器P1在运行一个处理http请求的线程T1,处理器P2在运行一个处理ssl请求的线程T2,那么当T1获得锁lockHttp的时候,锁的内容就会改变,为了保持缓存一致性,就会更新P2的缓存。那么,T2要获得锁lockssl的时候,发现缓存已经失效了,就必须从内存中重新加载缓存之类。总之,这会将缓存命中率降低到90%以下,引起性能的严重降低。而且发生这种事情的原因是因为我们不了解硬件的体系结构。
多cpu不能成倍提高速度的原因是任务的某些部分是必须串行处理的。比如,矩阵乘法可以分为三个部分,初始化矩阵,相乘,返回结果。这三部分第二部分可以用多线程来处理,第一部分和第三部分则是不可以的。而且第二部分必须在第一部分完成之后,第三部分必须在第一部分完成之后。那么,无论你添加多少个处理器,最快的时间都至少是第一部分和第二部分的时间之和。这个事实好像叫做Amdahl法则。
如果使用多线程,那么就必须考虑线程同步,而线程同步又是导致速度降低的关键。所以下面就讲述一些方法来加快多线程程序的吞吐速度。
方法一,把一个任务分解为多个可以子任务。
因为总有些子任务是可以并发的,多个子任务并发执行了很可能就能够避免cpu需要io操作的完成了,而且能够提高系统的吞吐量。
方法二,缓存多线程的共享数据。
当你已经在使用多线程了,很多时候必须使用共享数据。如果,数据是只读的,那么可以在第一次获取后保存起来,以后就可以重复使用了。但是,第一次的获取还是无法避免的需要线程同步操作的。
方法三,如果线程数目有限,就不要共享数据。
做法是为每一个线程实例化一个单独的数据,其实就是为每一个线程分配一块数据使用。这样没有线程同步操作了,速度可以尽可能的提示。
方法四,如果没办法确定线程数目到底有多少,那么使用部分共享吧。
部分共享其实就是使用多个资源池代替一个资源池,资源池的数目得更加经验来确定。如下图所示,
最后在提一个叫做Thundering Herd的问题,该问题维基百科有定义http://en.wikipedia.org/wiki/Thundering_herd_problem。大意是,当多个线程在等待一个资源的时候,如果事件等待到了,操作系统是唤醒所有等待的线程让它们自己去竞争资源了还是选择一个线程把资源给它。当然唤醒所有的线程肯定开销要大,而且所有没有抢到资源的线程还得重新进入等待状态,这无疑造成很多没必要的操作,浪费了没必要的线程上下文切换。总之,会不会存在Thundering Herd还是跟不同的操作系统有关的。万一存在Thundering Herd了,多线程可能就没那么好办了。
到现在我们知道了为什么多cpu并不能成倍提高程序的速度了。首先因为有些任务无法并行,其次即使是并行cpu之间还是有很多牵制的。本书的内容主要来自提高c++性能的编程技术一书。
如何提高多线程程序的cpu利用率的更多相关文章
- 多线程程序 怎样查看每个线程的cpu占用
可以用下面的命令将 cpu 占用率高的线程找出来: ps H -eo user,pid,ppid,tid,time,%cpu,cmd --sort=%cpu 这个命令首先指定参数'H',显示线程相关的 ...
- 多线程程序在单核cpu与多核cpu上是怎么工作的?
转自 1.多线程在单核和多核CPU上的执行效率问题的讨论 a1: 多线程在单cpu中其实也是顺序执行的,不过系统可以帮你切换那个执行而已,其实并没有快(反而慢) 多个cpu的话就可以在两个cpu中同时 ...
- 对于多线程程序,单核cpu与多核cpu是怎么工作的
此文中的大部分资料来自于网络上,我只是觉得把有道理的整理一下,方便以后查阅. 1.多线程在单核和多核CPU上的执行效率问题的讨论a1: 多线程在单cpu中其实也是顺序执行的,不过系统可以帮你切换那个执 ...
- jstack命令定位java程序CPU利用率高的代码位置
高手是怎么使用jstack精确找到异常代码的(java程序CPU利用率高的情况) 请jstack神器来帮忙 本文介绍Linux环境下使用jstack定位问题的秘笈1.[top命令]找到CPU利用率持续 ...
- DELPHI用const来提高应用程序在多核多线程下的性能
来自:http://bbs.csdn.net/topics/330048800 --------------------------------------------------------- 我们 ...
- python多进程提高cpu利用率
cpu参数: 1个物理cpu,2个逻辑cpu(超线程),单核 具体 http://blog.csdn.net/dba_waterbin/article/details/8644626 物理CPU. ...
- cpu利用率和cpu 队列
SIP的第四期结束了,因为控制策略的丰富,早先的的压力测试结果已经无法反映在高并发和高压力下SIP的运行状况,因此需要重新作压力测试.跟在测试人员后面做了快一周的压力测试,压力测试的报告也正式出炉,本 ...
- Linux下如何查看高CPU占用率线程 LINUX CPU利用率计算
目录(?)[-] proc文件系统 proccpuinfo文件 procstat文件 procpidstat文件 procpidtasktidstat文件 系统中有关进程cpu使用率的常用命令 ps ...
- linux系统性能监控--CPU利用率
在对系统的方法化分析中,首要且最基本的工具之一常常是对系统的 CPU利用率进行简单测量. Linux以及大多数基于 UNIX的操作系统都提供了一条命令来显示系统的平均负荷(loadaverage) . ...
随机推荐
- asp.net 文件上传示例整理
ASP.NET依托.net framework类库,封装了大量的功能,使得上传文件非常简单,主要有以下三种基本方法. 方法一:用Web控件FileUpload,上传到网站根目录. 代码如下 复制代码 ...
- PHP学习笔记 - 入门篇(3)
PHP学习笔记 - 入门篇(3) 常量 什么是常量 什么是常量?常量可以理解为值不变的量(如圆周率):或者是常量值被定义后,在脚本的其他任何地方都不可以被改变.PHP中的常量分为自定义常量和系统常量 ...
- C#之base关键字
1.base关键字用于从派生类中访问基类的成员. 2.调用基类上已被其他方法重写的方法. 3.指定创建派生类的实例是应调用基类的构造函数. 4.访问基类的公有成员和受保护成员,不能访问私有成员 5在静 ...
- [Bootstrap]全局样式(一)
页面必须设置为html5文档类型 <!DOCTYPE html> <html lang="zh-CN"> ... </html> 适应移动设备 ...
- Java知识思维导图
注:图片来源于网络,谢谢分享. 1 开发环境Java SDK 下载和安装2 环境变量的配置(path和classpath)3 编程基础 标识符命名规范4 Java数据类型5 运算符6 分支语句(if, ...
- python练习 根据日志中的ip和url排序
#!/usr/bin/env python #coding:utf-8 def open_file(file_name): res={} with open(file_name) as f: for ...
- SQL 存储过程加事务的使用
create proc USP_CUTTING_TATABLET_PULL_FINISH ( @name NVARCHAR(20) ) as SET XACT_ABORT ON--设置全盘回滚 BEG ...
- html 模板 swig 预编译插件 grunt-swig-precompile
GitHub grunt-swig-precompile NPM grunt-swig-precompile 在书写前端静态页面的时候,每个页面总在书写很多重复的标签. 为了提高效率,结合 swig. ...
- 【Delphi】无标题移动窗体
procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Inte ...
- wampsever在win10中安装扩展掉坑
1.必须要退出wampserver 2.php pecl + 3.wampserver 64 3.0.6