关​于​多​线​程​效​率​的​思​考

来源:互联网 发布:万网中文域名注册 编辑:程序博客网 时间:2024/06/05 18:25

在面试的时候被问了一个多线程的问题 
回来仔细思考了一下,多线程是否真的能提高了效率? 
我对多线程的理解就是: 
比如挖一个隧道,有2种开工方法 
1、只在山的一头挖,直至挖到山的另一头,从而打通隧道,这可以看成是单线程 

2、在山的两头挖,同时开工,最后在山的中间接通,从而打通隧道,这感觉肯定比1快了很多,好比多线程 

但是2成立的前提是必须有两个工人。而我们的计算机中一般来说只有一个CPU,也就是说只有一个工人。 
多线程不过是CPU在不同的时间片之间切换,而表现出齐头并进的样子。 

既然挖隧道的人只有一个,虽然我的施工方案是在山的两头开挖,但是由于工作的人只有一个,所以只有让这个人在山的两头跑,挖一会这头再去挖另一头,来回跑是要花费额外时间的(好比线程的切换和调度)。 

那么,我们是不是可以说,在单CPU的机器中,多线程反而降低了效率呢?

1.
不能一概而论,你的看多线程在你的程序中为啥而生。在单cpu系统,比如有io的等待,多线程也能提高效率 
2
楼主提的问题很有意思。经典的解释是 - 如果cpu确实是一个挖山工人,那么它工作就好像是挖1个小时,然后休息10个小时;这期间如果让它跑到山那头继续挖,效率还是很高的。

现在问题是 - 它是否工作1小时然后休息10小时?答案是肯定的。现在的程序时间大多花在读取数据上,真正的计算工作花时间还是相对少的,因此cpu很大时间表现都很闲,就像挖山,挖土效率高,运土效率低。多线程就是要充分利用它的挖土效率 
3
pc机不光只一个cpu,cpu和其它硬件设备一起才能完成计算,分工协作,但可能出现其中某个家伙偷懒或效率低,导致大家都等它,闲着的其它设备这个时 候可以腾出手来干其它活。单cpu在同一时刻只能干一件事情,这没有问题,问题是它并不是7*24*3600都在干活,其它设备也是同样的道理,多线程的 目的可以最大限度的提高硬件设备的利用率。
4
同一个设备可以同时干几件事情,但一个设备在同一时刻肯定只能干一件事情,一般我们说并行或串行,都在以时间段来看的而不是以时刻来看的,比如你一边上je消遣还一边写代码干活,在一定的时间范围内,你是并行的,但如果这个时间范围你划分得非常非常短,那么你是串行的 

5
一个cpu可以多线程。但是一个单核的cpu任何时间点,都只能在做一个任务。 
如果只是像楼主说的挖隧道这么简单的事,那么的确多线程没用。 
只不过很可惜,计算机不像拿铁锹挖隧道这么简单。 

6
假设每挖5分钟,就需要清理一下挖出来的石土。有一个小车在清理它们。 
工人只有一个。 
单线程的做法是: 挖5分钟。然后工人停止挖,小车清理石土的5分钟里,工人在等待。 
2个线程的做发是: 挖5分钟,小车来清理石土。这5分钟里,工人在另一头挖。 

也不是很恰当的比喻。不过至少能说明点问题。 
小车清理石土,就相当于磁盘io等相对于cpu计算来说比较慢的操作。 

cpu不会等着io的完成,而去执行另一个进程的计算任务。 
这边io完成时好象是会发出什么信号来着,忘了。计算机原理都还给老师了,惭愧啊。 
7

如楼主所举的例子,我来解惑。 

如果一个机器人代表CUP,哪么这个机器人一天所做的事情,并不都是只挖山。 

它还有许多事情要做,比如砍柴,烧水,钓鱼,挖山等等等。 

如果按以上划分是 4条线程, 每一个线程大概占用1/4CUP时间。 

如果你的设定 在挖山这一快 多设几次同一个任务。 比如设定到 挖山共有3条线程。 

哪么 挖山的CUP占用率将达到 1/2 这就是所谓的提高了效率。 

现实中的CPU 在大部分时候的 闲置状态的。 
因此 开多条线程能提高效率 不如说成是 充分利用了CPU执行时间。 

8
楼主举的例子是并行,在资源有剩余的情况下(比如人都堆到一个洞里干不开),肯定是提高效率。如果资源有冲突(人手只够从一个方向挖,比如只一个CPU),那就是并发了,不一定能提高效率。 

我想了个例子: 
    假设人手只够从一个方向挖洞。 
    挖洞时,总得把洞里的土运出去吧。洞越深,运土越占用时间,如果一大伙人都在那挖洞,等挖出一车土,然后一起坐着车运土(带装卸),那路上那些人就闲着了 (挖土时司机也会闲着)。为了提高工作效率,那就把人分成三组,一组人(一个挖土线程)挖土,两组人运土(两辆车,两个运土线程)。

9

我认为啊,单CPU单核、纯计算、没IO的理想状态下,单个线程肯定比多个线程快,因为省去了线程切换的开销。但真实的环境基本都有IO操作,在 异步的业务场景下,我一般会使用线程池,至于线程池的线程数目配置为多少,有资料推荐为N×(1+IO耗时/完整的业务耗时),N是CPU核数。

10
最简单的如web server,如果单线程的话,一个server同时只能接受一个用户的点击。
还点击率呢,直接就绿了。
另外多线程和快不快没有直接关系。最主要的是可以并发执行。
纯粹比较同一个任务在单线程还是多线程模式下快的话,肯定是单线程快。因为多线程会有一个线程调度的消耗。但是最为一个系统,多线程的优势是非常明显的。如果Java没有多线程直接可以去死了。
当年红极一时的plam系统因为对多线程支持的不好,在网络和媒体应用方面败下阵来。 

11

多线程效率 我认为未必会高,而且有时候相反会低。 
多线程并不是为了提高效率,而是不必等待 可以并行执行多条数据。 
可以这么想 我们通过xp系统复制文件。你可以复制一份文件 这叫是单线呈,但是你要等这个复制完了才能复制另一份文件,而且不能多复制。这样很难受,所以你可以选择多复制文件,这就是多线程。但复制多份文件用的时 间未必会比一份一份文件所用时间少。只是它合理利用了时间进行了多个操作。 
    如果是买票系统 就会用到多线呈。买票是同时进行的,如果一个用户一个用户等下去不是办法,所以可以多个用户同时买票,效率也就提高了。这里的效率不是执行的效率 而是时间的合理利用,多个线呈同时进行。 

12
单线程,多线程,线程池,都是不同问题的不同解决策略,不存在谁的效率一定高的问题.

一个时间服务器,一个线程处理请求就可以了
FTP,HTTP服务器,就不一样了,请求多,处理响应时间长,必须得有多个线程来处理,
线程池是多线程的一种改良方式
当然以上指的都是BIO的情况.
在NIO下,处理请求用单线程就可以了,因为它不存在IO阻塞的问题 

13
楼主的例子举的还算生动,但思路有点问题。在大多数场景中,各个线程不应该是同时去做同一件事情,而是各谋其职,协调工作,从而最大限度的利用系统资源。而系统资源并不仅仅是CPU,还有I/O或带宽等等。 

就楼主的例子而言,可以想象成两个线程,A线程的任务是挖,B线程的任务是把挖开的土石运走,从而提高效率,这也就是经典的生产者消费者模式。 

14
生产者-消费者模型,如果你是用多线程实现了的,那完全也可以写成单线程的(当然,单线程也就是一个顺序执行,恐怕不能称为“生产-消费”了)。 
    之所以设计成生产者-消费者的模式,是因为生产者和消费者不能步调一致吧?!因为会出现等待的情况,所以要按“生产者-消费者”的方式,用多线程实现(比 如3个生产者线程,2个消费者线程)。这充分利用了系统资源,如果效率还没有提高,那真不知道要干啥呢——比如说,生产者干的事就是 a+1,消费者干的事就是a-1,那何必费劲做成“生产者-消费者”呢(专门做出一个生产者线程对一个消费者线程,也太傻了吧)? 

    上面已经有人说了,系统运行环境下的资源并不只有CPU,还有网络,数据库(可能安装在另一个机器上)。数据库访问和网络的IO操作都是比较耗时的,这时候CPU会闲一些。使用多线程可以调配资源的使用率。 
    
    PS:假设你的程序部署到一个配置特牛的服务器上,感觉还是不足以应付业务量,结果一查CPU占用率,才3%,你的程序是不是写的很失败? 

15
我觉得lz举的例子不太合适,一个CPU它不是一个工人,按WINDOWS的比喻,一个CPU应该是100个工人. 
100个工人挖山从一头挖,最多同时能20个人一起挖,其他80个人休息.(这是单线程) 
如果两头挖,最多同时40人一起挖,60个人休息.(这是多线程) 
所以多线程只能提高CPU的使用效率. 
一头挖山只使用CPU的20%,两头挖山可能就会使用CPU的50%,因为启动一条新的线程也会有CUP开销. 
如果在工人足够多的时候,用多多线程,是可以提前完工的. 
如果在工人不足的时候,只能用单线程. 
声明下一个CPU它不是一个人!!! 

==================================================================================


多线程在单核和多核CPU上的执行效率问题的讨论

void TreadFuc1(PVOID param){_int64 sum=0;_int64 counter_begin,counter_end;QueryPerformanceCounter((LARGE_INTEGER*)&counter_begin);for(int i=0;i<100000000;i++){sum+=i;}SetEvent(evet1);}void TreadFuc2(PVOID param){_int64 sum=0;_int64 counter_begin,counter_end;QueryPerformanceCounter((LARGE_INTEGER*)&counter_begin);for(int i=0;i<100000000;i++){sum+=i;}SetEvent(evet2);}
双核机器上的测试:DualCore Intel Pentium E2160, 1800 MHz (9 x 200)
      测试1:开启两个线程同时分别执行TreadFuc1和TreadFuc2函数,测得执行完所花时间为0.451501s;顺序执行完 TreadFuc1和TreadFuc2函数,测得所花时间为0.850882s
      测试2:指定测试只运行在一个核上,测试步骤按照测试1进行,所对应的测试结果分别为为0.870268s,0.883862s

单核机器上的测试:AMD 1600MHz
      测试:开启两个线程同时分别执行TreadFuc1和TreadFuc2函数,测得执行完所花时间为0.967732s;顺序执行完 TreadFuc1和TreadFuc2函数,测得所花时间为0.958844s


结论:双核上的多线程明显可以提高程序性能,从0.451501s和0.850882s的时间对比就能看的出来
迷惑:为什么单核上的多线程性能提高并不明显呢?我预期的是并行执行比顺序执行要快很多,可是测试结果并不是这样





下面是测试代码,有兴趣的可以一起讨论和研究下

int main(int argc, char* argv[]){   DWORD dwSet=1;   int p=SetProcessAffinityMask(GetCurrentProcess(),dwSet);//设置CPU的亲和力将dwSet的值分别设置为1,2,3看双核CPU的每个核的使用率_int64 sum=0;_int64 counter_begin,counter_end,large;evet1=CreateEvent(NULL,FALSE,FALSE,NULL);evet2=CreateEvent(NULL,FALSE,FALSE,NULL);evet11=CreateEvent(NULL,FALSE,FALSE,NULL);evet22=CreateEvent(NULL,FALSE,FALSE,NULL);DWORD dwP1=0,dwS1=0,dwP2=0,dwS2=0;QueryPerformanceFrequency((LARGE_INTEGER*)&large);QueryPerformanceCounter((LARGE_INTEGER*)&counter_begin);   //多线程并行执行部分_beginthread(TreadFuc1,0,NULL);_beginthread(TreadFuc2,0,NULL);WaitForSingleObject(evet1,INFINITE);WaitForSingleObject(evet2,INFINITE);QueryPerformanceCounter((LARGE_INTEGER*)&counter_end);double time=(double)(counter_end-counter_begin)/large;printf("main Time is %I64d,%lf\n",counter_end-counter_begin,time);int sign1=GetProcessAffinityMask(GetCurrentProcess(),(LPDWORD)&dwP1,(LPDWORD)&dwS1);sign1=GetProcessAffinityMask(GetCurrentProcess(),(LPDWORD)&dwP2,(LPDWORD)&dwS2);QueryPerformanceCounter((LARGE_INTEGER*)&counter_begin);     //顺序执行部分TreadFuc1(NULL);TreadFuc2(NULL);QueryPerformanceCounter((LARGE_INTEGER*)&counter_end);time=(double)(counter_end-counter_begin)/large;printf("main Time is %I64d,%lf\n",counter_end-counter_begin,time);printf("main thread exit.\n");return 0;}

多线程在单cpu中其实也是顺序执行的,不过系统可以帮你切换那个执行而已,其实并没有快(反而慢)
多个cpu的话就可以在两个cpu中同时执行了..............
单核CPU上运行的多线程程序, 同一时间只能一个线程在跑, 系统帮你切换线程而已, 系统给每个线程分配时间片来执行, 每个时间片大概10ms左右, 看起来像是同时跑, 但实际上是每个线程跑一点点就换到其它线程继续跑

效率不会有提高的
切换线程反倒会增加开销

#3楼说的是对的。所以一般没有必要的话,尤其在单核CPU的时候,不推荐使用多线程。
单核CPU时使用多线程,通常是有线程要处于等待状态。
而对于普通的进度条更新类的,能够简单控制的(比如:在循环里面手动处理消息)就简单控制,一般不使用线程,这样可以提高程序的性能。并且避免掉不必要的线程同步问题。

===================================================================================================================

最近写一个文件处理程序,需要处理大量的文本文件,每个文本文件都有编号(0.txt....) 

于是自然想到多线程来处理,假如指定n个线程,那么第i个线程处理的文件对应是:i.txt,(i+n).txt,... 
但事实上,我发现多线程处理的效率明显低于单线程,代码大体如下,大家看看问题出现在哪里:


//
那当然,如果是纯粹是指CPU时间上的占用,肯定是单线程有优势,因为线程切换,同步都要占用CPU时间,多线程的优势在于用户体验和响应的并发性。


//
采用多线程是因为,一个线程不太可能占用全部的CPU时间,当线程空闲的时候,可以把CPU让给别人,如果一个线程本来就占用全部的CPU,那多线程就没用了。 


如果对磁盘访问采用多线程,那效率更是急下降,因为磁盘是机械的,那样会频率移动磁头,当移动磁头的时间比读写磁盘的时间还要长的时候,性能将指数下降。你可以这样做个实验,用两个线程拷贝光盘中的文件,这样表现很明显,因为光盘比磁盘更慢。 
注:如果同时播放两个MP3,对效率的影响看不出来,因为数据流量的确是太小了,磁盘本身还有空闲时间。 


多线程是基于一种假设:每个线程的资源(当然包括CPU)使用率都非常低,而且实时性要求不是太高。

/
你的这个情况建议一个线程负责IO,一个线程负责处理数据。 
这样的两个线程应该比一个线程的效率要高。 

不要几个线程都IO,因为这样反而会降低效率。




================================================================================


待测试问题 


多线程处理接收数据模型,有没有单线程快?因为考虑到单线程工作可能不会留下空闲时间。待测试。
对多个线程的优先级进行设置,以不让其他程序影响。

============================================================================================

看看多线程的效率有多差劲!

(本随笔对多线程的胡扯多有误导,各位朋友喷喷算了,能不信就别信。。。哈哈哈。。)

 

  最近,网上流出了各酒店的开房客户信息,号称有2000W。。本着做贼心虚的心态,上网找了找。。下载下来是几个 CSV 文件。。都是300M左右。不管用记事本打开还是用其它文本工具打开,都是当的痛苦。。


试着写个小工具搜索这些文件。。为了提高用户体验,就想到了多线程。。7个文件,开7个线程分别读取。。

  试了一下,所有文件一起搜索,大概需要3分钟查询结束。。如图:


本以为是我这台已经用了两年的机器太烂,没在意。。

  刚才偶尔手贱,选了一个文件就点“查询”了,结果很快,8秒多,一个300M的文件就完了。。

  吓了一跳。。

  感觉心理差距有点大。。

  又试了一下,还是8秒多;选两个文件,22秒多;选3个文件,40多秒。。。

  7个文件,还是要3分钟左右。。。


多线程对效率影响这么大?郁闷了!

  找度娘问了问,她说:“如果有大量的线程,会影响性能,因为操作系统需要在它们之间切换”,尼码!这么轻描淡写!

  于是,试着将搜索放在一个线程里,读完一个文件,接着读另一个文件,改完,测试。

  果然,不到 1 分钟就执行OK了。测了多次,最多的也只要1分零几秒。。

恐怖了,多线程处理性能竟然浪费这么严重。。看来以后要谨慎使用了!

  度娘的轻描淡写让我轻轻的把它给忽略了。。尼妹!

  一个手贱,长了一个姿势。。哈哈。。

 

  更让我谢天谢地的是:开房记录里木有找到我。。。哈哈哈哈。。。

=====================================================================================

我在一个项目中有大量的数据要处理
  对一个数组进行一定的逻辑运算
 一开始我用单一的过程来处理,大体是这样的
for i:=0 to 7
 for j:=0 to 100
    {
   处理过程
   }
耗时大约为40ms
我想再次优化所以我把处理过程分为8 份建立8个线程来处理
每个线程负责处理一部分数据,结果耗时为50ms左右,反而更慢;
这是为什么呢???? 难道多线程更没效率?????

只有一个CPU的情况下,多线程的作用是当你和一些慢的外设交换信息时可以节省很多时间
就你的例子来说,你的数据估计都在缓存中,所以多线程还多耗用了操作线程的时间

如果设计得很精确的系统的话使用单CPU的机器,多线程当然会将低效率。但是在现实情况下,非常精确的系统难于设计,使用多线程的可以使得软件系统设计简单得多。
使用多CPU的情况下,可以提高效率。

除了最新的那个什么超线程P4CPU(在XP里你会看到有2个CPU,可惜假的),其他CPU都不能同时执行几个线程,都是交替执行,只是因为他快,给人的错觉就是同时执行。不过很快就有双核心CPU用了,那时候你用2线程应该会快很多。


多线程并不一定是高效的

我曾开发的LYProxy,作为研究的

使用单线程的代理服务器,仅有一个线程就能处理多个连接请求,发现他的效率没比多线程的差

所以多线程并不一定就好,需要看场合的,以后的双内核CPU就有用了,现在的基本都是单U机,没明显作用

当然,例如网络下载,如果是对方限制单一线程的速度;或因为路由的不同导致速度有快慢等,那就有用的

http://lysoft.7u7.net

多线程在多CPU的情况下可以显著提高效率
单CPU的情况下
是将CPU的空闲时间给非主线程或较低优先级的线程使用
但同时带来一些消耗的问题
比如线程的创建,分配资源,同步等待
所以设计不合理的线程反而效率更差
只有当要处理的过程非常耗时才使用线程
如果不是很耗时
可以采取其他的技巧让程序看起来不是很耗时。。。

在线程切换时需要一定的CPU开销,所以一般尽可能少用线程。在以下情况可以适当采用线程
用异步操作减少用户等待时间,例如Outlook Expresss是轮流收每一个帐号的邮件,而Outlook 2003是同时收取所有帐号的邮件
用异步操作减少用户取消操作之前必须等待的时间,例如资源管理器在用户短时间内选择多个目录节点时只显示最后一个目录的内容
用异步操作抢占服务器资源,例如多线程下载。














0 0
原创粉丝点击