计算一个数组所有元素之和(方法总结)

时间:2022-10-25 00:18:28

    上面两个帖子均以计算一个给定数组元素之和的例子 来展示多核处理器(多处理器)并行计算的方法。由于只是演示,在基于实际操作系统的场合下,这两种方法都需要有一定的变更。

    第一个例子,在计算一个数组元素之和的场合下使用旋锁,在一定程度上有些不合适。由于上锁和解锁所花费的开销可能是从数组中获取相应元素,然后加到指定地点所花费指令周期的2倍,甚至更多。对于一个旋锁,它只能放在非cache存储区域内,那么如果它正好处于SDRAM或DDRAM,那么访问所花费的开销会更大,因此单单上锁、解锁的花费就超过了计算本身的开销。要注意的是,在计算每一个元素值的时候,都需要分别对索引值和结果值上锁和解锁。在多任务场合下,可能在上锁前和解锁后需要关中断和开中断。

    第二个例子在无操作系统,每个核单任务的场合下有绝对的优势,但是在基于操作系统,实时多任务的场合下将会吃亏。我们可以设想一下,如果核A中的计算数组的子作业开始后,(假设给核B发送一个消息,激活核B的相应计算子作业),核B的计算线程也开启。如果其中一个核中的任务安排有些吃紧,比如说核B,那么在它计算到一半时,甚至刚开始没多久,就被其它更高优先级的任务打断,那么我们可以想象,当核A中的计算任务结束后,它会等核B任务的结果若干长的时间。因此对于这种方法,基本上要设计成两个线程能够被任意核调度,也就是说会出现在一个核的任务队列中同时出现计算给定数组前50项的和的子作业,又会出现计算给定数组后50项和的子作业的两个任务。现在这种安排比较多,我也比较推荐。这样可以避免其中一个子作业长时间的罢工而影响任务的整体效率。

    第一种方法,也就是使用共享计算例程的方法,它的优势首先很明显,可移植性更高,更直观,概念更完整。而在运行效率上,如果上锁和解锁时间明显地小于计算时间,那么对于多处理器环境下也会有非常好的表现,它可以体现出计算机指令流水线般的魅力。现在假设核A与核B同时调用这个计算例程(暂时还是以计算数组元素之和为例)。理想状态下,当核A在获取索引值时,核B的例程调用中阻塞;核A取完索引值,然后开始取数组元素,此时核B开始获取下一个索引值;核A计算好第一个数组元素并放入结果,此时B开始取第二个元素,随后将刚才核A计算好的结果将第二个值进行相加获得第二个结果;核A同时又开始取第三个元素了……

    怎么样,与指令流水线很像吧!第一种共享例程的方法在多任务场合下也体现出较强劲的优势,尤其是有较多的处理器或核的情况下。我们可以设想,比如现在有三个核(对称),其中核A的一个任务调用了这个共享计算例程,而核B稍后加入计算,然后核A又去做其它事情了,但是并不妨碍计算,也就是只要有一个处理器去对这个例程进行调用,那么这个计算结果就会线性地继续下去,就好像是串行地输出结果。而第二种方法更像是并行地得到结果。对于每个子作业片,只有当它们全部完成后才能得到一个总的结果。其中就可能包含了一些任务的调度频率问题,而第一种方法却没有这个问题。在极端情况下,其中一个核可以始终调用一个计算任务,而另一个核却忙得不可开交,那么这是,采用共享例程的方法显然可能胜过子划分任务法。