这篇文档描述了 CPU 核心数量、并发数量以及性能的关系。主要有统筹方法以及阿尔达姆定律。

统筹方法

我国著名的数学家华罗庚使用泡茶的例子来说明统筹法,如下图所示:

)

很明显使用统筹法,有相互依赖关系的部分使用串行,而没有相互依赖关系的部分使用并行,这样统筹安排节省了时间,提升了效率。使用统筹法对我们的程序并行计算是有很好的指导作用的。

阿姆达尔定律(Amdahl's Law)

这个定律是计算机界的一个经验法则,它代表了处理器并行运算后效率的提升能力。理论最大加速比是通过下面这个公式计算而来的:

这个公式中各个元素的含义如下:

● N : 处理核心数的数量
● P:可以加速时间占比

我们来写一个程序来举例:

import time
from concurrent.futures import ProcessPoolExecutor

def _task():
    time.sleep(1)

if __name__ == '__main__':
    start = time.time()
    for _ in range(10):
        _task()
    end = time.time()
    print('took: {}'.format(end - start))
    pool = ProcessPoolExecutor(10)
    start = time.time()
    futures = []
    for _ in range(10):
        future = pool.submit(_task)
        futures.append(future)
    for future in futures:
        future.result()
    end = time.time()
    print('took: {}'.format(end - start))

运行程序之后,我们得到了使用并行优化前后的时间占比,P 的计算如下:

P = 1.1267099380493164 /  10.02167558670044  ~= 0.1124

然后我们将 P 代入到公式中去,就得到了最大优化占比,如下:

S(10)  =  1 / ((1 - 0.112427) + 0.112427 / 10) ~= 1.1125

我们看到最大优化占比和我们的实际优化占比是非常接近的。如果我们不断的加大这个公式中的 N 的数值,就会得到一个曲线,发现 N 的数量并不是越大越好的。如下图所示:

总结

通过上面的分析,我们知道并不是线程数量越多,效率就越高的。线程的数量和 CPU 核心数量是有关系的,一般我们会采用下面的经验值:

● CPU 密集性的程序,我们采用 N + 1
● IO 密集性的程序,我们采用 2N + 1

线程过多,会引起线程之间去竞争 CPU 资源,会抵消一部分的优化效率。另外,线程过多会有上下文频繁的切换,这也是需要我们去考虑的成本。

最后更新于:
2022.06.14