推荐想学多核技术的人先看一下这个。
多核革命
2001 年, IBM 推出了基于双核的 Power4 处理器;随后 Sun 和 HP 都先后推出了基于双核架构的 UltraSPARC IV 以及 PA-RISC8800 处理器。但这些面向高端应用的 RISC 处理器曲高和寡,并没有能够引起广大群众的关注。直到 2005 年第二季度, Intel 发布了基于 X86 的桌面双核处理器,从此多核才走进平常百姓家。
在今天多核处理器已占据了越来越多的市场份额,作为一线 的编程人员,我们必须直面多核革命带来的冲击。多核编程,既是机遇也是挑战,如何在这个行业大变革中把握方向、与时俱进,成为摆在我们面前的迫切课题。因 为从单核到多核并不像处理器时钟频率的提升那样对程序员而言是透明的,如果我们的编写的程序没有针对多核的特点来设计,那就不能完全获得多核带来的性能提升。 在这个新旧交替的战国时代,我们有什么选择、能否借鉴以前的开发经验?
是的,人类最为伟大的技能就是能够借鉴之前的经验。我们应该借鉴前人的经验,积极学习并行编程技能同时在实际工作中小心求证、谨慎行动。多核,特别是双核,与双路 SMP (对称多处理器)架构非常相似:
图 1 Intel 和 AMD 的双核 CPU 结构示意图
从 图 1 可以看到尽管 Intel 与 AMD 的双核技术有所不同,但仍然可以发现所谓双核处理器就是将两个运算核心集成在一个处理器上。这跟在一块主板上集成两颗处理器的双路 SMP 系统相当相似,不同之处仅在于双核系统两个计算核心之间相互交换数据并不需要通过前端系统总线( FSB ),而双路系统的两个处理器是通过 FSB 来交换数据的,这也是我们编写程序时需要注意的一个小细节。
就像针对 SMP 编程一样,针对多核处理器编程也必须使用多线程或者多进程的形式来编写应用程序才能够得到多核带来的性能提升。可见我们在 SMP 并行编程上积累的经验大多都可以应用到多核编程上来。
编程的变革
多核时代的到来,给我们的编程思维带来了巨大的冲击。为了能够充分地利用多核性能,我们必须学会以分块的思维设计程序、以多进程或多线程的形式来编写程序。到底应该使用多进程还是多线程的形式来编写程序是最让程序员感到困惑的问题之一, 我觉得需要根据具体的应用来决定;但通常情况下使用多线程进行多核编程比使用多进程有更大的优势:
A) 线程的创建和切换开销比进程更小。
B) 线程间通信的方式多而且简单也更有效率。
C) 多线程有汗牛充栋的基础库支持。
D) 多线程的程序比多进程的程序更容易理解和修改。
除了编程形式,我们使用多线程编程的动机也发生了改变。 在以往,对于 Windows 程序员来说,使用多线程的主要原因之一是为了提高用户体验:如在长时间的计算中提高 UI 、 I/O 或者网络的响应速度。而在多核时代我们编写应用程序为了充分利用多个计算核心,缩短计算时间或者在相同的时间段内计算更多任务。如在游戏编程时通过多线程的方式把碰撞检测的计算分散到多个 CPU 内核可以大大缩减计算时间;也可以利用多核做更细致的检测计算,从而能够模拟更加真实的碰撞。
在多核时代,我们对编程语言的选择也要更加谨慎。这一小节的内容虽然是个人见解但的确值得系统开发、游戏开发甚至 Web 开发程序员一起探讨。 无论开发何种项目,相对于 C/C++/Fortran 等编译型语言, C#/java/Python 等脚本语言也许是更好的选择。 原因在于脚本语言比较高级,一般都提供了对多线程的原生支持;如 C# 的 System.Threading.Thread 、 java 的 java.lang.Thread 及 Python 的 Threading.Thread 。相形之下,编译型语言往往都是通过平台相关的库来提供多线程支持,如 Win32 SDK 、 POSIX threads 等。没有统一的标准,造成使用 C/C++ 编写多线程程序需要考虑更多的细节,提高了项目成本。从现在来看, C/C++ 的用户虽然不少,但在多核时代脚本语言会更受欢迎,因为船小好调头啊,脚本语言一般都没有 ISO 标准,说改就可以改,很快就会出现针对多核的解释器和编译器了。不过 PHP/Ruby/Lua 等脚本语言就会比较难得到多核程序员们的宠爱了——因为它们并没有提供内核级线程支持,它们的多线程是用户级的甚至不支持线程,用它们编写的多线程程序仍然无法完全利用多核优势。
表 1 各种语言对多线程支持的比较
|
|
C/C++ 等编译型语言 |
C#/java/Python 等脚本 |
PHP/Ruby/Lua 等脚本 |
|
语言支持多线程 |
否 |
是 |
否 |
|
库支持多线程 |
是 |
是 |
否 |
|
支持内核级线程 |
是 |
是 |
否 |
|
支持用户级线程 |
可模拟 |
可模拟 |
是 |
|
线程编程复杂度 |
一般 / 易 |
易 |
N/A |
|
推荐度 |
★★★☆ |
★★★★ |
★☆ |
虽然 C/C++ 在多线程编程方面因为没有从语言级提供支持而失去了部分优势;但因为当前的主流操作系统都以 C 语言接口的方式提供创建线程的 API ,而 C/C++ 又有相当丰富的程序库,也就一定程度上弥补了语言上的不足。使用 C/C++ 编写多线程程序不仅可以使用 Win32 SDK ,还可以使用 POSIX threads 、 MFC 和 boost.thread 等。 虽然这些库都提供了一定程度的封装,减轻了程序员进行多线程负担,但对于目标定位于提升计算密集型程序的性能的多核程序员来说,这些方式仍然太为复杂。因为使用这些库几乎要增加一倍的关键代码,相应地调试和测试的成本也大大增加。更好的选择应该是使用 OpenMP 这种通过编译器加强来支持多线程的基础库。 OpenMP 通过使用 #pragma 编译器指令来指定并行代码段,对程序的改动相当少;而且可以指定编译为串行版本以方便调试,更可以和不支持 OpenMP 的编译器共存。
可见即便脚本语言在语言层次上提供了对多线程编程的原生支持,但却并没有比 C/C++ 领先多远。根本原因在于脚本语言的基础——数据结构与算法的基础库 与 CRT/STL 等 C/C++ 基础库然一样是以串行形式来设计开发的 。针对多核编程去修改基础库这一几乎所有编程语言都需要面对的燃眉之急是拉开两大阵营领先优势的生死之战,而所有权集中于某一公司或者组织的 C#/java/Python 这类脚本语言船小好调头,估计将赢得这场关键之役。这就是我在上文推荐选择使用脚本来编写程序的原因之一。
随着多核处理器占据市场主导地位,编程人员面临新的挑战。本文探讨了多核编程的基本概念,对比了多进程与多线程编程的优劣,并讨论了在多核时代选择合适的编程语言的重要性。
76

被折叠的 条评论
为什么被折叠?



