并行计算的难点与数学原理解析
大约在五年前的那段时期内,计算速度的你追我逐曾一度陷入僵局。直到那个时候,设计师还一直是通过人尽皆知的三种技术来实现狂飙的性能:缩小本来已经非常微小的晶体管、在每颗处理器中整合更多数量的晶体管以及让它们以更高的频率运行。
问题是,更高的处理器性能意味着更大的功耗和更多发热量,即使你在芯片烧焦之前找到了一种方法来解决掉发热量过大的问题,延续这种趋势也会造成成本过高以及对环境的破坏过大。
另一种实现更快计算性能的方法也已经有一段时间的历史了。这种方法并不是让处理器突破速度极限,而是采用更多的处理器。大型计算机与服务器长期以来一直采用众多的处理器来处理繁重的工作。然而芯片技术的进步让人们能够在单一芯片中集成多个处理器,这种方法不仅效率更高而且还便宜很多。当今,高性能计算的方式是将计算任务进行分割,然后交由诸多处理器核心进行处理。假如是个人计算机,这意味着不仅CPU能够拥有大量核心,而且图形处理器(GPU)也能够包含数十个,甚至是数以百计的核心。
然而,多处理器硬件所带来的问题是软件上的巨大挑战。从20世纪40年代现代计算的初期开始,各种程序就一直是设计成顺序执行的方式。美国国防部高级研究计划署提供了大部分资金用来开发包含大量处理器的系统,并取得了一定的成功。在这类系统中,计算任务被分割成诸多细小部分,这些细小的任务可以同时运行,这些系统旨在通过这种方式来解决计算难题。然而,这些大规模并行系统没有能够在商业市场中生根发芽。
原因之一便是最常见的计算难题以及用于解决这些难题的算法不能很好地适应这种「分割」的处理方式。而顺序的想法似乎已经在我们的大脑中根深蒂固。神经系统科学家Jill Bolte Taylor指出,大脑的右半部分能够处理感官信号,它所做的是并行处理。而大脑的左半部分负责分析想法,「其运行方式就像是一个串行处理器。」不管是好还是坏,编程都是一项左脑的活动。
并行方法在数学上的最大障碍便是,许多进程是递归的:每一步都依赖上一步的结果。考虑一下找出两个整数的最大公约数这一简单问题。解决这一问题的标准方法是欧几里德算法,这种算法已经有2,000多年的历史,所使用的是重复减法。
例如,如果你想要找出2,987与1,751的最大公约数,那么可以先用2,987来减1,751。重复地减掉差数(视需要颠倒顺序,以防出现负数),直到结果为零。在这一例子中,这两个数的最大公约数是103。这是一个完美而高效的方法,但是它是一个天生的串行式方法,因为每一次减法都依赖于上一次的结果。
串行思想虽然占据主导地位,但是也有例外。最好的例子便是图形。在图形中,一个非常简单、常见以及典型的需求就是旋转图像。如果你还记得一些三角学的话,你可能会想起一个简单的公式,将某个点逆时针旋转一个角度& Theta:
其重点在于,每个点的处理都可以独立于所有其它点之外。如果你的处理器数目与点数一样多的话,那么整个转换过程即可在一个大规模并行运算中完成计算。诸多更加复杂的图形任务也是如此。
图形任务的并行友好性特点导致了早期人们在图形处理器(GPU)中融入多处理器架构。NVIDIA®(英伟达™)顶级Tesla GPU目前包含240个处理器核心。虽然这些核心并不像CPU处理器那样灵活,但是它们在特定任务上却更胜一筹,例如诸多计算密集型难题当中重要的向量运算。
无论是针对CPU还是GPU来说,能够有效利用大量核心的软件仍然是个难题,但是情况已经变得越来越好。NVIDIA®(英伟达™)凭借着CUDA™并行编程模型以及C语言扩展充当开路先锋,该模型让通用计算能够在NVIDIA®(英伟达™)GPU上运行,而其C语言扩展则消除了对这种处理器进行编程的门槛。因此,开发人员能够分别通过CUDA™工具包以及PGI的CUDA™ Fortran编译器来利用C、C++以及Fortran语言对NVIDIA®(英伟达™)CUDA™ GPU进行编程。同时还能够利用诸多驱动程序级的API,例如OpenCL以及DirectCompute。
软件开发人员所面临的最大难题之一便是在现有应用程序上实现更高性能以及开发出更多全新的计算密集型应用程序。无论是选择多核CPU还是核群GPU,除了考虑将其应用程序实现并行化以外,他们别无选择。根据近几年的发展,CUDA™并行编程模型已经成为一款公认的「更简单的」并行编程方式(它仍然不简单,但是CUDA™的确使特定操作变得更加简单)。而且,与CPU相比,GPU还能够提供巨大的性能优势。因此这两大元素的有机结合为开发人员提供了一条开发更多创新应用程序的途径。