今天有同学问我: 阿姆达尔定理是如何应用到并行软件的开发呢?这是一个非常好的问题。因为在并行软件的开发中我们常常会深陷于各种形式同步所导致的崩溃。而没有精力去分析并行是否真的带来收益。以至于在大部分情况下只能粗暴的放弃并行开发。所以阿姆达定理留给人们的宝贵财富渐渐被人们所遗忘。希望今天这篇简短的文章能够帮助你得到一些关于并行开发的启示。 这里以pelagia中的PRFESA示例作为基础进行演示。你可以在最新版本的pelagia中的" src\prfesa.c"中找到这个示例。 先回忆一下阿姆达尔定理的内容。在wiki上他是这样定义的:“阿姆达尔定律是计算机系统设计的重要定量原理之一,于1967年由IBM360系列机的主要设计者阿姆达尔首先提出。该定律是指:系统中对某一部件采用更快执行方式所能获得的系统性能改进程度,取决于这种执行方式被使用的频率,或所占总执行时间的比例。 阿姆达尔给出了如下公式:S=1/(1-a+a/n) 其中,a为并行计算部分所占比例,n为并行处理结点个数。这样,当1-a=0时,(即没有串行,只有并行)最大加速比s=n;当a=0时(即只有串行,没有并行),最小加速比s=1;当n→∞时,极限加速比s→ 1/(1-a),这也就是加速比的上限。例如,若串行代码占整个代码的25%,则并行处理的总体性能不可能超过4。这一公式已被学术界所接受,并被称做阿姆达尔定律(Amdahl law)。” 首先创建了两个宏用于表示定理中的变量n和a。他们分别是: - #define TEST_CORE 10
- #define TEST_BLOCK 100
复制代码TEST_CORE表示并发的核数。TEST_BLOCK表示阻塞时间的长度。因为在阿姆达尔定理中的a中的串行部分很难在软件工程中进行量化。所以用TEST_BLOCK来表示可并行部分的运行时间。虽然a很难量化但我们可以根据公式在稍后的部分里进行反推得到它。
其中block的代码如下: - //block
- void* p = malloc(1024 * 1024 * 64);
- short* s = (short*)p;
- for (long long i = 0; i < TEST_BLOCK; i++) {
- *s = plg_crc16(p, 1024 * 64);
- }
- free(p);
- //block
复制代码当TEST_BLOCK为零的时候,可以近似的看作整个系统在没有用户的并行状态下。只有系统的状态下并行与串行的消耗总和。因为当TEST_BLOCK为零的时候所有系统的并行和串行的消耗都是由系统API产生的。
设定TEST_BLOCK为0,TEST_CORE为10得到系统运行的时间2.4。 设定TEST_BLOCK为0,TEST_CORE为1得到系统运行的时间5.3。 设定TEST_BLOCK为100,TEST_CORE为10得到系统运行的时间2.7。 设定TEST_BLOCK为100,TEST_CORE为1得到系统运行的时间10.6。 将数据汇总如下: 将TEST_BLOCK为0的数据代入到阿姆达尔公式。我们可以得到TEST_BLOCK为0时系统并行计算部分所占比例。计算如下: 1/(1/(1-a+a/10))=2.4/5.3 a = 0.6 获得TEST_BLOCK为0时,TEST_CORE为10时,系统的并行加速比为 S = 1/(1-0.6+0.6/10) = 2.17,即并行化带来了2.7倍的性能提升。 同理我们可以得到TEST_BLOCK为100时的a = 0.83, S= 3.9。即并行化带来了3.9倍的性能提升。 当软件工程中并行部分所占比例较高时可以获得很好的加速比。当软件并行部分所占比例较低时。加速比趋于1,并行所带来的加速效果趋于零。
最后需要注意的是pelagia虽然可以调整线程数量但仍然受限于系统硬件。因为使用的测试机的硬件核心数量为4。TEST_CORE为4, TEST_BLOCK为100时获得的时间为3.3。已经非常接近TEST_CORE为10的加速效果。
转眼已经在gameres.com上灌水15年。
花有重开日,人无再少年。
相逢拌酩酊,何必备芳鲜。
|