鲁班学院 java架构师成长路线-Java阿姆达尔定律java
阿姆达尔定律能够用来计算处理器平行运算以后效率提高的能力。阿姆达尔定律因Gene Amdal 在1967年提出这个定律而得名。绝大多数使用并行或并发系统的开发者有一种并发或并行可能会带来提速的感受,甚至不知道阿姆达尔定律。无论怎样,了解阿姆达尔定律仍是有用的。算法
我会首先以算术的方式介绍阿姆达尔定律定律,而后再用图表演示一下。缓存
阿姆达尔定律定义网络
一个程序(或者一个算法)能够按照是否能够被并行化分为下面两个部分:架构
能够被并行化的部分并发
不能够被并行化的部分ide
假设一个程序处理磁盘上的文件。这个程序的一小部分用来扫描路径和在内存中建立文件目录。作完这些后,每一个文件交个一个单独的线程去处理。扫描路径和建立文件目录的部分不能够被并行化,不过处理文件的过程能够。优化
程序串行(非并行)执行的总时间咱们记为T。时间T包括不能够被并行和能够被并行部分的时间。不能够被并行的部分咱们记为B。那么能够被并行的部分就是T-B。下面的列表总结了这些定义:线程
T = 串行执行的总时间code
B = 不能够并行的总时间
T- B = 并行部分的总时间
从上面能够得出:
T = B + (T – B)
首先,这个看起来可能有一点奇怪,程序的可并行部分在上面这个公式中并无本身的标识。然而,因为这个公式中可并行能够用总时间T 和 B(不可并行部分)表示出来,这个公式实际上已经从概念上获得了简化,也便是指以这种方式减小了变量的个数。
T- B 是可并行化的部分,以并行的方式执行能够提升程序的运行速度。能够提速多少取决于有多少线程或者多少个CPU来执行。线程或者CPU的个数咱们记为N。可并行化部分被执行的最快时间能够经过下面的公式计算出来:
(T – B ) / N
或者经过这种方式
(1 / N) * (T – B)
维基中使用的是第二种方式。
根据阿姆达尔定律,当一个程序的可并行部分使用N个线程或CPU执行时,执行的总时间为:
T(N) = B + ( T – B ) / N
T(N)指的是在并行因子为N时的总执行时间。所以,T(1)就执行在并行因子为1时程序的总执行时间。使用T(1)代替T,阿姆达尔定律定律看起来像这样:
T(N) = B + (T(1) – B) / N
表达的意思都是是同样的。
一个计算例子
为了更好的理解阿姆达尔定律,让咱们来看一个计算的例子。执行一个程序的总时间设为1.程序的不可并行化占40%,按总时间1计算,就是0.4.可并行部分就是1 – 0.4 = 0.6.
在并行因子为2的状况下,程序的执行时间将会是:
T(2) = 0.4 + ( 1 - 0.4 ) / 2
= 0.4 + 0.6 / 2
= 0.4 + 0.3
= 0.7
在并行因子为5的状况下,程序的执行时间将会是:
T(5) = 0.4 + ( 1 - 0.4 ) / 5
= 0.4 + 0.6 / 6
= 0.4 + 0.12
= 0.52
阿姆达尔定律图示
为了更好地理解阿姆达尔定律,我会尝试演示这个定定律是如何诞生的。
首先,一个程序能够被分割为两部分,一部分为不可并行部分B,一部分为可并行部分1 – B。以下图:
在顶部被带有分割线的那条直线表明总时间 T(1)。
下面你能够看到在并行因子为2的状况下的执行时间:
并行因子为3的状况:
优化算法
从阿姆达尔定律能够看出,程序的可并行化部分能够经过使用更多的硬件(更多的线程或CPU)运行更快。对于不可并行化的部分,只能经过优化代码来达到提速的目的。所以,你能够经过优化不可并行化部分来提升你的程序的运行速度和并行能力。你能够对不可并行化在算法上作一点改动,若是有可能,你也能够把一些移到可并行化放的部分。
优化串行份量
若是你优化一个程序的串行化部分,你也可使用阿姆达尔定律来计算程序优化后的执行时间。若是不可并行部分经过一个因子O来优化,那么阿姆达尔定律看起来就像这样:
T(O, N) = B / O + (1 - B / O) / N
记住,如今程序的不可并行化部分占了B / O的时间,因此,可并行化部分就占了1 - B / O的时间.
若是B为0.1,O为2,N为5,计算看起来就像这样:
T(2,5) = 0.4 / 2 + (1 - 0.4 / 2) / 5
= 0.2 + (1 - 0.4 / 2) / 5
= 0.2 + (1 - 0.2) / 5
= 0.2 + 0.8 / 5
= 0.2 + 0.16
= 0.36
运行时间 vs. 加速
到目前为止,咱们只用阿姆达尔定律计算了一个程序或算法在优化后或者并行化后的执行时间。咱们也可使用阿姆达尔定律计算加速比(speedup),也就是通过优化后或者串行化后的程序或算法比原来快了多少。
若是旧版本的程序或算法的执行时间为T,那么增速比就是:
Speedup = T / T(O , N);
为了计算执行时间,咱们经常把T设为1,加速比为原来时间的一个分数。公式大体像下面这样:
Speedup = 1 / T(O,N)
若是咱们使用阿姆达尔定律来代替T(O,N),咱们能够获得下面的公式:
Speedup = 1 / ( B / O + (1 - B / O) / N)
若是B = 0.4, O = 2, N = 5, 计算变成下面这样:
Speedup = 1 / ( 0.4 / 2 + (1 - 0.4 / 2) / 5)
= 1 / ( 0.2 + (1 - 0.4 / 2) / 5) = 1 / ( 0.2 + (1 - 0.2) / 5 ) = 1 / ( 0.2 + 0.8 / 5 ) = 1 / ( 0.2 + 0.16 ) = 1 / 0.36 = 2.77777 ...
上面的计算结果能够看出,若是你经过一个因子2来优化不可并行化部分,一个因子5来并行化可并行化部分,这个程序或算法的最新优化版本最多能够比原来的版本快2.77777倍。
测量,不要仅是计算
虽然阿姆达尔定律容许你并行化一个算法的理论加速比,可是不要过分依赖这样的计算。在实际场景中,当你优化或并行化一个算法时,能够有不少的因子能够被考虑进来。
内存的速度,CPU缓存,磁盘,网卡等可能都是一个限制因子。若是一个算法的最新版本是并行化的,可是致使了大量的CPU缓存浪费,你可能不会再使用x N个CPU来得到x N的指望加速。若是你的内存总线(memory bus),磁盘,网卡或者网络链接都处于高负载状态,也是同样的状况。
个人建议是,使用阿姆达尔定律定律来指导咱们优化程序,而不是用来测量优化带来的实际加速比。记住,有时候一个高度串行化的算法赛过一个并行化的算法,由于串行化版本不须要进行协调管理(上下文切换),并且一个单个的CPU在底层硬件工做(CPU管道、CPU缓存等)上的一致性可能更好。