关于多线程在多核cpu上执行效率的问题

前言:博主最近在比较python和go语言写的web服务器的执行效率问题,在看了google搜索结果后,产生了疑问

1.为什么python的异步执行框架tornado效率可以和go语言媲美?

2.为什么随着线程的增加,并发数的增长呈现逐步缓慢的趋势?

带着这些问题,博主探究了下原因,如果有错误,欢迎大家指出。

注意:为简化推理过程和理解,以下只考虑执行任务的线程,系统中其他所有(包括系统线程)均不考虑,即cpu只执行我们的任务线程。

一、单核cpu

首先,我们要知道在单核时,只能进行并发执行某个线程(操作系统的时间片轮转法是分配时间片给线程而不是进程,博主有文章提到过),而不能并行执行。

1.当线程为cpu密集型时(  比如一个  while( true ){ i++;}  )

(图中横坐标是时间,从0s到1s,方块是线程每次时间片的执行)

扫描二维码关注公众号,回复: 10561731 查看本文章

由于时间片轮转,虽然cpu中只有这一个线程在执行,可它还是每执行一个时间片后就被调度出cpu,再调度回来,这样在1s内时间被用来执行线程+调度线程,cpu一直在执行线程和调度,利用率为100%(看吧,我们单线程就把cpu跑满了),此时如果增加线程,执行效率不会得到提升,反而可能因为调度变复杂、内存等资源争夺而降低效率!

2.当线程为IO密集型时(比如一个从磁盘拷贝数据到另一个磁盘的拷贝进程)

(图中横轴为时间,从0s到1s,方块为线程占用cpu执行,波浪线为线程正在IO(此时cpu为空),该线程只有IO结束才能继续执行,波浪线与方块之间的时间为调度时间)

从图中可以发现,cpu利用率极低,1s内时间被用来执行线程+IO+调度,此时如果对当前任务用多线程,只要磁盘足够快,那理论上1s内cpu利用率越高,效率越高,但是实际上磁盘读写速度有限,如果增加过多线程,cpu利用率是上去了,但是磁盘因为要切换多个线程的读写(由于线程被调度),导致效率降低,木桶效应,影响整个任务效率。

3.当执行线程为计算多,IO少(其实本质就是计算密集型比如一个web服务器,执行各种数学运算并返回结果)

此时若采用单线程,那图和2中类似,只不过方块变大,波浪变小;

此时若采用多线程,比如两个线程时

(如图,方块间为cpu调度时间,波浪线为IO时间)

从图中,因为IO少,我们考虑此时磁盘肯定后于cpu满载,所以随着线程的增加,cpu利用率变高,理想状态下,1s时间被用来执行线程+调度,此时IO和执行并行了,极大提高了CPU利用率,因而可知,cpu密集而IO少的线程合理使用多线程可以增加cpu使用率和任务执行效率,至于多少个线程合适,则应在实际的硬件和系统下进行测试。

4.当线程为cpu执行少,IO多时(其实本质就是IO密集型,比如一个从磁盘拷贝数据到另一个磁盘的拷贝进程)

参考2,方块变更小了,波浪更长了,此时执行效率同样受制于磁盘,若磁盘未满载,则继续增加线程可以增加cpu使用率和磁盘使用率,加快任务效率,但若磁盘满载,则继续增加线程整体执行效率反而降低。

二、多核CPU

以八核为例,

1)若只跑一个线程,那同一时间只有某一核被利用,其他七核都空闲;

2)若同时跑八个计算密集型,则理论上整个任务执行效率会提高八倍,若超过八个线程,则效率可能反而下降;

3)若同时跑八个IO密集型,若没超过磁盘负载,则还可以继续增加线程,同时执行效率得到提高,若超过了,则执行效率会急剧下降;

注意:以上IO密集和cpu密集只是举例子,密不密集不是靠个人感觉,计算量大不大也不是靠个人感觉,实际上,例子中IO密集线程代表的情况是:使在cpu满载前,磁盘先满载的线程;cpu密集线程代表的情况是:使磁盘满载前,cpu先满载的线程;

举个例子:一个线程要就算圆周率后一百亿亿位,由于内存只有1g,所以要不断把中间结果写回磁盘在某台cpu差,硬盘读写速度超级高的设备上(外星人的科技,读写速度为无穷大),是cpu密集型;在另一台运算超级厉害的cpu(也是外星人科技,计算圆周率后一百亿亿位只要1ms的那种),然而磁盘却很慢(1kb/s),那它反而变成了IO密集型

现在大家说的IO密集型和cpu密集型是针对21世纪的大众硬件来说的,虽然没那么极端,但是还是想让大家知道,要具体问题具体分析,IO密集和cpu密集也只是相对的,而且要判断多线程能否提高执行效率,首先要知道这个线程在执行任务的机器上是io密集型还是cpu密集型

发布了98 篇原创文章 · 获赞 68 · 访问量 54万+

猜你喜欢

转载自blog.csdn.net/jarniyy/article/details/104910177