单核CPU,多线程与性能
问题概述
单核CPU的计算机上, 多线程能够提高程序运行的性能吗? 这个问题看起来简单,实际很复杂,设计到多方面的因素. 首先我们要把概念搞清楚, 那就是什么是性能? 一般来说, 我们把运行一个任务所花的时间来评价性能, 所花的时间可以是在CPU上, 也可能是在I/O操作上, 运行任务的程序, 也可能同时在运行另外若干的任务(吞吐量). 这里我们把概念给缩小一下:
我们这里把性能限制在一个程序运行一个任务, 这个任务是只消耗CPU资源(CPU bound), 所花的时间越小, 说明性能越好. 为了纯粹地说明问题, 我们排除了数据共享问题, 即线程之间不做任何同步动作, 完全隔离.
从理论上说,如果计算机只执行这一个测试程序, 那么单线程要比多线程性能好,因为多线程需要做线程上下文环境的切换; 而当计算机同时运行其他的进程, 假设其他进程里也有多个大量消耗CPU的任务, 那么我们的程序由于是多线程, 抢到CPU时间片的机会增多, 它的性能应该好于单线程.
理论上是这么回事, 但我们知道, 实践与理论是有差距的, 我们的测试不可能在真空环境中. 操作系统的实现有高度的戏剧性, 谁也不能预测实际的测试一定与理论相符, 另外在我们实际的运行环境中,各种情况导致的系统差异很大, 因为我们必须做一些测试.
MSDN上有一篇著名的文章<<Win32 Multithreading Performance>>, 里面讲的东西与我们很相近.它主要论述的是串行计算和并行计算的性能比较, 我们直接拿它的例子, 进行一些更改, 来测试我们的假设.
首先讨论我们测试的主题与它的不同, 主要有2点: 1, 我们讨论的任务是一个固定的任务, 而它里面讨论的是数个计算量不同的任务, 而计算不同的任务涉及到吞吐量的概念; 2, 我们讨论的是线程数量之间的比较(分别测试不同数量的线程), 而它只有单线程与多线程的比较.

图1: 多个不同的任务并行处理

图案2: 一个固定的任务并行处理
测试程序介绍
一个任务在这里简化为一个持续占用CPU的计算, 为了测试的准确性, 中间不可以有任何的I/O操作, 例如:
for (int iCounter=0; iCounter<iLoopCount; iCounter++);
给定的任务量iDelay,单位是毫秒, 有一段模拟的代码, 从而把一秒的时间转换为循环数iLoopCount.里面所用的两个API是QueryPerformanceFrequency和QueryPerformanceCounter.
我们增加一个方法来取代OnWorstcase:
void CThreadlibtestView::OnFixTask()
{
if(!m_iNumberOfThreads)
{
MessageBeep(-1);
return;
};
for (int iLoop=0;iLoop<m_iNumberOfThreads;iLoop++)
{
m_iNumbers[iLoop]=(int)&m_tbConc[iLoop];
m_tbConc[iLoop].iId=iLoop;
if(iLoop==0)
m_tbConc[iLoop].iDelay=m_iDelay/m_iNumberOfThreads+m_iDelay%m_iNumberOfThreads;
else
m_tbConc[iLoop].iDelay=m_iDelay/m_iNumberOfThreads;
m_tbConc[iLoop].tbOutputTarget=this;
m_tbConc[iLoop].iStartOrder=0;
m_tbConc[iLoop].iEndOrder=0;
m_tbConc[iLoop].iTouchCount=0;
};
}
另外我们指定特定的任务量和线程数量:
int iTaskSize[]={100,500,1000,2000,4000};
int iThreadSize[]={2,5,10,15,20};
单线程时候我们调用OnSerial(), 多线程时调用OnConcurrent(), 线程数量分别取iThreadSize里的值.
测试次数仍然保持10次, 取平均值, 整个测试我们分别运行两次, 第一次在负载很轻的计算机上运行, 第二次在同样的计算机上加载一个大负载的进程, 此进程里有十个线程, 每个线程都是基于CPU的密集计算, 程序如下:
DWORD WINAPI ThreadFunc(LPVOID lpParam)
{
DWORD busyTime=10;
while(true)
{
DWORD startTime=GetTickCount();
for(;GetTickCount()-startTime<=busyTime;)
;
Sleep(1);
}
return 0;
}
特别要注意的是, 两次计算不能各启动一个进程, 必须在一个进程中, 因为在程序开始,我们会算出1秒对应循环数, 而每次启动程序这个数字是不同的, 为了更有意义的比较,我们要求这个数字一定相同.
测试环境: CPU Intel Pentium M 1.7 G; 1047472KB RAM, Windows 2000 professional SP4.
一秒的循环数:146278208
测试结果

图3: 在负载轻的系统上测试结果

图4: 在负载重的系统上测试结果
结论和建议
根据测试结果,我们可以得出一些结论(针对单核CPU):
在负载轻的系统上, 多线程不适合处理基于CPU的任务,而在负载重的系统上,多线程可以帮助提高性能.
这是一个模糊和慎重的结论, 因为测试结果里的一些现象我也给不出合适的理由, 应该属于操作系统”戏剧化”和”不确定性”的表现吧(操作系统会对某些线程动态提高优先级,但本例中的线程优先级保持不变.), 例如在负载轻的机器上, 20个线程和2个线程运行时间差异不大; 在负载重的机器上, 2个线程运行时间比单线程还长, 而当线程数量增加到5时, 性能才有显著的提高.
所以我的建议是,在单核CPU机器上,处理CPU密集的任务时, 不推荐使用多线程, 除非你对目标机器非常的了解和确定,并经过严格的测试. 当然, 涉及到其他I/O操作的任务, 比如等待用户按键, 读取文件, 网络通讯等, 多线程才是正当其选的解决方案.
单核CPU,多线程与性能的更多相关文章
- 单核cpu多线程有必要吗?
问题分析 现代计算机一般都是多核cpu,多线程的可以大大提高效率,但是可能会有疑问,那单核CPU使用多线程是不是没有必要了,假定一种情况,web应用服务器,单核CPU.单线程,用户发过来请求,单个线程 ...
- 多线程程序在单核cpu与多核cpu上是怎么工作的?
转自 1.多线程在单核和多核CPU上的执行效率问题的讨论 a1: 多线程在单cpu中其实也是顺序执行的,不过系统可以帮你切换那个执行而已,其实并没有快(反而慢) 多个cpu的话就可以在两个cpu中同时 ...
- 对于多线程程序,单核cpu与多核cpu是怎么工作的
此文中的大部分资料来自于网络上,我只是觉得把有道理的整理一下,方便以后查阅. 1.多线程在单核和多核CPU上的执行效率问题的讨论a1: 多线程在单cpu中其实也是顺序执行的,不过系统可以帮你切换那个执 ...
- “多个单核CPU”与“单个多核CPU”哪种方式性能较强?
多个单核CPU: 成本更高,因为每个CPU都需要一定的线路电路支持,这样对主板上布局布线极为不便.并且当运行多线程任务时,多线程间通信协同合作也是一个问题.依赖总线的传输,速度较慢,且每一个线程因为运 ...
- 单核CPU并发与非并发测试
多线程运行程序的目的一般是提高程序运行效率并且能够提高硬件的利用率比如多核CPU,但是如果我们只有单核CPU并发运行程序会怎样呢? 我以两个环境作为对比: 环境A(我本机8c) 环境B(我的云服务器1 ...
- 单核、多线程与时间片,以Node.js为例
去年写了篇文章<线程与进程的理解>,当时认为线程和CPU的单核多核无关,操作系统可以有很多个线程.但今天看<深入浅出Node.js>一书时,多次提到单线程无法利用多核CPU一类 ...
- 原来 CPU 为程序性能优化做了这么多
本文主要来学习内存屏障和 CPU 缓存知识,以便于我们去了解 CPU 对程序性能优化做了哪些努力. 首先来看下 CPU 缓存: CPU 缓存 CPU 缓存是为了提高程序运行的性能,CPU 在很多处理上 ...
- zabbix监控单核cpu使用率和多核cpu总负载
zabbix自带的基础监控的模板中只有对单核cpu负载1分钟.5分钟.15分钟的监控. 添加对总的cpu负载的监控 key:system.cpu.load[all,avg1] 1分钟cpu总的负载 添 ...
- ixgbe 82599 固定源与目标, UDP, 64字节小包, 1488w pps 单核CPU软中断sirq 100%
ixgbe 82599 固定源与目标, UDP, 64字节小包, 1488w pps 单核CPU软中断sirq 100% 注: 测试使用, 正常应用不要开启 五元组不同, 开启ntupleethtoo ...
随机推荐
- 电脑是如何识别USB 3.0 U盘的
USB 3.0电缆如图1所示. 图1 USB 3.0的接口比USB 2.0接口多了5根线,这5根线分别是Shield.SSRX+/-和SSTX+/-,即是屏蔽地.超速发送差分对和接受差分对. 因此一个 ...
- poj3254Corn Fields(状压)
http://poj.org/problem?id=3254 第一个状压题 思路挺好想 用二进制表示每行的状态 然后递推 用左移 右移来判断是不是01间隔出现 c大神教的 我的代码WA在这个地方了.. ...
- C# 系统应用之通过注册表获取USB使用记录(一)
该文章是“个人电脑历史记录清除软件”项目的系统应用系列文章.前面已经讲述了如何清除IE浏览器的历史记录.获取Windows最近访问文件记录.清除回收站等功能.现在我需要完成的是删除USB设备上的U盘. ...
- [NYOJ 43] 24 Point game
24 Point game 时间限制:3000 ms | 内存限制:65535 KB 难度:5 描述 There is a game which is called 24 Point game ...
- 步步为营 SharePoint 开发学习笔记系列总结
转:http://www.cnblogs.com/springyangwc/archive/2011/08/03/2126763.html 概要 为时20多天的sharepoint开发学习笔记系列终于 ...
- 采用软件nginx实现web服务器集群
nginx:软件负载均衡器 是高并发量http/反向代理服务器.实现windows下IIS的负载均衡 条件:2台服务器 1.cpu:Inter(R) 酷睿 i5 cpu 2.26GHz 内存:2G ...
- 处理MVC中默认的Json方法返回时间的问题
利用 Json方法返回 数据时,如果有时间格式,会变成 "\/Date(1369419656217)\/" 这个样子,问了同事找到个解决方法 using Newtonsoft.Js ...
- Java&MySQL Type Mapping
MySQL Type Name Return value of GetColumnClassName Returned as Java Class BIT(1) (new in MySQL-5.0) ...
- 字符串逆转(递归和非递归java)
package 乒乒乓乓; public class 递归逆转字符串 { //非递归逆转 public static String reverse(String s) { ...
- UVa11404 - Palindromic Subsequence(区间DP+打印路径)
题目大意 给定一个字符串,要求你删除尽量少的字符,使得原字符串变为最长回文串,并把回文串输出,如果答案有多种,则输出字典序最小的 题解 有两种解法,第一种是把字符串逆序,然后求两个字符串的LCS,并记 ...