通常情况下,并行代码是否可能比串行代码运行得更慢?我的情况就是这样,我真的很困惑!我应该怎么办呢?
通常情况下,并行代码是否可能比串行代码运行得更慢?我的情况就是这样,我真的很困惑!我应该怎么办呢?
在并行模型中决定性能的三个关键因素包括:
并行任务粒度
并行任务的粒度必须足够大,才能抵消并行化带来的开销(例如,并行任务创建和它们之间的通信)。由于分布式内存(DM)模型中进程之间的通信开销通常比线程同步更高,因此进程的任务粒度应该更高。同时,这种粒度也不应威胁到负载均衡。
简而言之:你需要使并行任务足够“大”,以证明并行化的开销是值得的。
通讯开销
当一个进程要与其他进程通信时,会有创建/发送消息的成本,在使用同步通信例程时,还存在等待其他进程接收消息的成本。因此,为了提高MPI应用程序的性能,需要减少进程之间交换消息的数量。
可以在进程之间使用计算重复项,而不是等待从特定进程返回结果,这个结果可以直接在每个进程中执行。当然,在交换结果的开销超过计算本身所需时间时,这通常是有道理的。另一种解决方案是使用异步通信替代同步通信。在同步通信中,发送消息的进程等待直到其他进程接收它;而在异步通信中,进程在返回发送调用后立即恢复执行,从而使通信与计算重叠。然而,要利用异步通信可能需要重写代码,并且仍然很难实现很好的重叠比率。
可以通过使用更高性能的通信硬件来减少通信开销,但这可能成本高昂。集体通信也可以提高通信性能,因为它基于硬件、网络和拓扑优化通信。
简化版: 减少并行任务之间的通信和同步,采用冗余计算、异步通信、集体通信和更快的通信硬件。
进程之间的负载平衡
良好的负载平衡对于最大化并行工作至关重要。负载平衡受到任务分布和应用程序运行的资源集合的影响。
在一组固定资源的应用程序中,应该重点关注任务分配。如果任务具有大致相同的计算量(例如迭代),则只需要在进程之间执行最相等的任务分配。
但是,某些应用程序可能在具有不同速度处理器的系统中运行,或者可能具有具有不同计算量的子任务。针对此类情况,可以使用任务“farming模型”来促进更好的负载平衡,因为它可以使用动态任务分配实现。但是,在这种模型中,使用的通信量可能会危及效率。
另一个解决方案是手动进行任务分配调整。这可能会变得复杂和困难。但是,如果资源集合不具有速度均匀性,并且在应用程序执行之间不断变化,则任务分配调整的性能可移植性可能会受到影响。
简化版:每个进程完成工作的时间应该大致相同。
正如其他人所指出的那样,並行代碼比串行代碼慢的原因有幾個。
如果您正在進行矩陣操作,您可能希望通過“阻塞”代碼更有效地利用CPU高速緩存。根據CPU高速緩存大小,您可以潛在地獲得3到4倍的性能提升。阻塞基本上是將矩陣分成小塊或塊來處理,使它們適合高速緩存。這減少了必須讀取/寫入主記憶體的次數,從而產生性能改進。
另一個選擇是使用GPU。
上述解決方案適用於大部分計算是浮點或整數操作的情況下表現良好。
對於通用計算,理想情況下,您希望設計您的應用程序是自適應的,以便在運行時它確定是否有性能增益在分布工作負載,只有在有利時才分布。