Amdahl's Law

Amdahl's Law

Amdahl's Law can be used to calculate the ability of processors to increase efficiency after parallel operations. Amdahl's Law is named after Gene Amdal in 1967. The vast majority of developers working with parallel or concurrent systems have a feeling that concurrency or parallelism might bring speedups without even knowing Amdahl's law. Regardless, it's useful to understand Amdahl's law.

I'll first introduce Amdahl's law mathematically, and then demonstrate it graphically.

Amdahl's Law Definition

A program (or an algorithm) can be divided into the following two parts according to whether it can be parallelized or not:

  • part that can be parallelized
  • parts that cannot be parallelized

Suppose a program processes files on disk. A small part of this program is used to scan paths and create file directories in memory. After doing this, each file is handed over to a separate thread for processing. The parts of scanning paths and creating file directories cannot be parallelized, but the process of processing files can.

We denote the total time for the serial (non-parallel) execution of the program as T. Time T includes times that cannot be parallelized and parts that can be parallelized. The part that cannot be parallelized is recorded as B. Then the part that can be parallelized is TB. The following list summarizes these definitions:

  • T = total time of serial execution
  • B = total time that cannot be parallelized
  • T- B = total time of the parallel part

From the above it can be concluded that:

T = B + (T - B)

At first, this may seem a little strange, the parallelizable part of the program does not have its own identity in the above formula. However, since the parallelizable can be expressed in terms of the total time T and B (the non-parallel parts) in this formula, the formula has actually been conceptually simplified, meaning that the number of variables is reduced in this way.

T-B is the parallelizable part, and executing it in parallel can improve the running speed of the program. How much speedup you can get depends on how many threads or how many CPUs are executing. We denote the number of threads or CPUs as N. The fastest time for the parallelizable part to be executed can be calculated by the following formula:

(T – B ) / N

or in this way

(1 / N) * (T – B)

The second way is used in the wiki.

According to Amdahl's Law, when a parallelizable portion of a program is executed using N threads or CPUs, the total execution time is:

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 缓存浪费,你可能不会再使用 xN 个 CPU 来获得 xN 的期望加速。如果你的内存总线(memory bus),磁盘,网卡或者网络连接都处于高负载状态,也是一样的情况。

我们的建议是,使用阿姆达尔定律定律来指导我们优化程序,而不是用来测量优化带来的实际加速比。记住,有时候一个高度串行化的算法胜过一个并行化的算法,因为串行化版本不需要进行协调管理(上下文切换),而且一个单个的 CPU 在底层硬件工作(CPU 管道、CPU 缓存等)上的一致性可能更好。

 

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=326919315&siteId=291194637
law