有关多线程的一些期刊文章,和大家分享一下,希望有所帮助
第9卷第2期
2009年6月
Vol 9,No 2南京工业职业技术学院学报
Jun ,2009
JournalofNanjingInstituteofIndustryTechnology
文章编号:1671-4644(2009)02-0051-03
多核系统的多线程并行计算分析
朱葛俊,张 力,盛昀瑶
(常州机电职业技术学院 信息工程系,江苏 常州 213164)
摘 要:基于多核系统下编程环境的变化,比较了各类编程语言对并行计算的支持情况,并利用多线程实现了多核系统下定积分计算,结果表明在多核环境下多线程技术有良好的应用价值。关键词:多核系统;并行计算;多线程;定积分中图分类号:TP311 11 文献标识码:A
多核处理器的出现已彻底颠覆了计算行业长期以来的一个规则,即要提高软件性能就需要开发新一代硬件。在此之前,提高硬件性能大多依靠提高处理器的时钟速度,这是整个计算史上处理器演进的一大特点,然而近两年来这种情况正在改变。
功耗和散热问题引起了越来越多的关注,原本的处理器工程离开了提高处理器速度的轨道,而转向通过增加每块芯片上执行内核的数量来提高并行处理能力。随着多核架构的持续演进,开发人员需要把线程技术作为解决方案的核心(而不仅仅是一种可使用的特性)来进行优化,而线程制作、同步和锁定、线程粒度、调度和进程管理等相关问题将随着时间的推移日益突出,而且对并行可扩充性的规划将会
[1]
变得越发重要。
对于内核数量日益增多的系统,最重要的开发策略就是使可靠的线程实践走向常规化和制度化。可靠的线程实践不仅可带来解决方案性能的短期提升,还能随着所需线程数量
[2]
的增加,在未来优化上述解决方案的线程设计。
进程来构建并发程序的另外一个缺陷就是:进程间的通讯通常都比较低效。
1 1 2 线程(Thread)
定义:线程有时也被称为轻量进程(lightweightproces-ses),指运行中的程序的调度单位。线程必须存在于某个进程中。在基于线程的并发过程中,计算任务被分解成同一个进程间的多个线程来执行,线程间的调度由操作系统内核来进行。由于多个线程都存在于同一进程空间中,它们共享该进程的进程空间,所以它们自己的通讯可以通过进程中的共享资源来进行。基于线程的并发过程中的一个缺陷就是:当一个线程不慎破坏了某个数据时,会同时影响到进程间的其
[3]
他线程使用该数据。
到底应该使用多进程还是多线程的形式来编写程序是最
让开发人员感到困惑的问题之一,本文觉得需要根据具体的应用来决定,但通常情况下使用多线程进行多核编程比使用多进程有更大的优势,这是因为:
(1)线程的创建和上下文切换的开销比进程小得多。(2)线程间通信的方式多,而且简单也更有效率,不需要繁琐的IPC通信。
(3)多线程有庞大的基础库作为支持。
(4)多线程的程序比多进程的程序更容易理解和修改。1 2 编程动机的变化
除了编程形式,使用多线程编程的动机也发生了改变。以往,对于程序员来说,使用多线程的主要原因是为了提高用户体验:如在长时间的计算中提高UI、I/O或者网络的响应速度。而在多核时代编写应用程序却要求充分利用多个计算核心,缩短计算时间或者在相同的时间段内计算更多任务。如在碰撞计算中利用多线程的方式把粒子碰撞检测的计算分散到多个CPU内核可以大大缩减计算时间;也可以利用多核做更细致的检测计算,从而能够模拟更加真实的碰撞。同时,软件开发人员对于编程语言的选择也要更加谨慎。无论开发何种项目,相对于C/C++/Fortran等编译型语言,C#/Java/Python等脚本语言也许是更好的选择。原因在
1 多线程编程的介绍
1 1 编程形式的变化
在多核系统中,为了能够充分地利用多核性能,必须以
分块的思维设计程序、以多进程或多线程的形式来编写程序。现代操作系统中为构建并发程序提供了一般提供了两种机制:
1 1 1 进程(Process)
定义:进程是程序在内存中的一次运行。进程是系统对资源分配的最小单位。一个进程可以包含多个线程。在基于进程的并发过程中,我们将一个计算任务分解成多个独立的进程来执行,它们之间的调度由操作系统内核来进行。由于进程都拥有独立的进程空间,所以如果一旦它们想和外界通讯,就必须使用某种显示的进程间通讯(IPC:inter-processcommunication)机制,这是基于进程来设计并发程序的一个缺陷:进程间的通讯会增加程序构建过程中的复杂性;基于
收稿日期:
2009-03-25
基金项目:江苏省教育厅 青蓝工程 资助项目
:(男,,,
有关多线程的一些期刊文章,和大家分享一下,希望有所帮助
52
南京工业职业技术学院学报 第9卷第2期
[5]
这样,每个矩形面积的和就近似等于该积分的值。
如图1所示:梯形积分 每一竖条都拥有固定宽度的
于脚本语言比较高级,一般都提供了对多线程的原生支持;如C#的System.Threading.Thread、Java的http://ng.Thread及Python的Threading.Thread。相形之下,编译型语言往往都是通过平台相关的库来提供多线程支持,如Win32SDK、POSIXthreads等。没有统一的标准,造成使用C/C++编写多线程程序需要考虑更多的细节,提高了项目成本。如表1,当前来看,C/C++的用户虽然不少,但在多核时代脚本语言会更受欢迎,因为船小好调头。脚本语言一般都没有ISO标准,可以马上进行更改,很快便会出现针对多核的解释器和编译器。不过PHP/Ruby/Lua等脚本语言就会比较难以发挥多核系统的性能,因为它们并没有提供内核级线程支持,它们的多线程是用户级的,甚至不支持线程,用它们编写的多线程程序仍然无法利用多核优势。
表1 几种语言多线程的比较
C/C++/FortranC#/Java/PythonPHP/Ruby/Lua
语言级多线程库支持多线程支持内核级线程支持用户级线程线程编程难易度
否是是是较难
是是是是容易
否否否是一般
梯级 。每个竖条的高度便是被积函数的值。将所有竖条的面积加在一起便得出曲线下面积的近似值,即被积函数的值.根据牛顿莱布尼茨公式,我们有:
2
104/(1+x)=
也就是图1所示的被积函数的积分值为 ,下面分别用串行和并行两种方法去实现计算。
1 3 现有基础语言对多核的支持
虽然C/C++/Fortran在多线程编程方面因为没有从语言级提供支持而失去了部分优势;但因为当前的主流操作系统都以C语言接口的方式提供创建线程的API,而C/C++又有相当丰富的程序库,也就一定程度上弥补了语言上的不足。使用C/C++编写多线程程序不仅可以使用Win32SDK,还可以使用POSIXthreads、MFC和boost.thread等。虽然这些库都提供了一定程度的封装,减轻了程序员进行多线程的负担,但对于目标定位于提升计算密集型程序性能的多核程序员来说,这些方式仍然太为复杂。因为使用这些库几乎要增加一倍的关键代码,相应地调试和测试的成本也大大增加。更好的选择应该是使用OpenMP这种通过编译器加强来支持多线程的基础库。OpenMP通过使用#pragma编译器指令来指定并行代码段,对程序的改动相当少;而且可以指定编译为串行版本以方便调试,更可以和不支持OpenMP的编译器共存。需要指出的是即便脚本语言在语言层次上提供了对多线程编程的原生支持,但却并没有比C/C++领先多远。根本原因在于脚本语言的基础 数据结构和算法的基础库与STL等C/C++基础库然一样是以串行形式来设计开发的。所以针对多核编程去改进基础库这几乎成了所有编程语言都需要面对的燃眉之急,而所有权集中于某一公司或者组织的C#/Java/Python这类脚本语言则相对来说比较容易
[4]
作出这一方面的改变。
图1 梯形积分
2 2 定积分串行单线程的实现
以下是该算法的串行实现,使用C语言:staticlongnum_steps=100000;doublestep;voidmain(){
int;i
doublex,p,isum=0.0;
step=1.0/(double)num_steps; for(i=0;i<=num_steps;i++){ x=(i+0.5)*step; sum=sum+4.
0/(1.
0+x*x);
}
pi=step*sum;
printf("pi=%f\n",}
pi=3 141613
2 3 定积分并行多线程的实现
以下是并行多线程实现,使用Java语言:publicclassPI{
staticlongnum_steps=100000; staticdoublestep;
staticdoublesum=0 0; staticintpart_step;
staticclassPITaskextendsThread{ intpart_number; doublex=0 0; doublesum=0 0;
pi);
2 多核并行计算的应用
2 1 梯形积分
在微积分中,我们知道一个定积分在几何上可以表示为曲线下面积。也就是说,积分的近似值可以通过计算得出。我们先将积分面积划分为许多的梯级,并在每一梯级内画出
有关多线程的一些期刊文章,和大家分享一下,希望有所帮助
第9卷第2期 朱葛俊,张 力,盛昀瑶:多核系统的多线程并行计算分析 publicPITask(intpart_number){ this part_number=part_number; }
publicvoidrun(){ for(inti=part_number;=part_step){
i<num_steps;i+
53
的线程库,无疑加重了程序员的负担。Java语言在设计之初
便内置了多线程支持。作为Java技术的一个重要组成部分,线程在语言(语法)级别和Java虚拟机,以及类库(classlibrary)级别上均能够得到支持。Java线程与POSIXpthread有很多相似之处。Java类别库提供的线程类别可以支持丰富的方法集,用以启动、运行或停止线程,并检查线程的状态。最重要的是Java语言的跨平台型可以使代码不需经过修改便可运行在多个平台之上。大大降低了程序移植的工作
[6]量。
x=(i+0 5)*step; sum+=4 0/(1 0+x* } }
}
publicstaticvoidmain(String[]args){ int;i
doublep;i
x);
3 结束语
对于处理器主频来说,摩尔定律已经接近极限了。传统的处理器,只有一个内核,这个内核也只能够同时运行一个
线程。多核处理器可以在一个处理器上嵌入多颗采用超线程
(
)
技术的内核。这样,多核处理器就可以同时运行多个的线程。这意味着,传统的单线程的程序,将无法利用未来多核CPU多线程并发执行的能力。单线程程序将会极大地浪费多核CPU的运算能力!
多核处理器对操作系统和程序设计等都提出了很多挑战,需要思考怎么解决这些问题。应对多核处理器的软件开发,除了编程语言级别的多线程支持以外,还有几种解决思路,包括硬件隐藏、自动并行、OpenMP技术、MPI集群、新并行语言等。一些新的高生产率和支持全局地址空间的并行程序语言已经出现了,而且正在快速发展,这些技术为我们现在乃至将来高效地利用硬件资源提高劳动生产率提供了可靠的解决途径。
参考文献:
[1]王鹏.并行计算应用及实战[M].北京:机械工业出版社,2008.
[2]张云泉.多核时代计算环境的改变[J].程序员,2007(4):28-30.[3](美)WILKINSONB.并行程序设计[M].北京:机械工业出版社,2002.[4](美)GOSLINGJ.Java编程语言[M].北京:中国电力出版社,2003.
[5]颜庆津.数值分析[M].北京:北京航空航天大学出版社,2006.
[6]林信良.Java学习笔记[M].北京:清华大学出版社,
2007.
step=1 0/(double)num_steps; part_step=Runtime getRuntime availableProcessors(); PITask[]art_sums=newPITask[art_step]
for(i=0;i<part_step;i++){(part_sums[i]=newPITask(i)) start();
i<part_step;i++){
}
for(i=0;
try{
part_sums[i] join();
}catch(InterruptedExceptione){}
sum+=part_sums[i] sum; }
pi=step*sum; System out println(pi); }
}
3 1415926535981615
2 4 程序分析
C语言程序是古老而又经典的系统语言,其语言本身并没有对线程机制提供支持,但可以通过外部函数库提供相应的支持,但各平台上的C线程库标准不一,种类繁多,如Linux系统提供符合POSIX标准的Pthread线程库或NPTL线程库,Windows平台提供win32threadAPI或更高级的MFC类库封装。程序员在不同平台上编写多线程程序需掌握不同
AnalysisMult-iThreadParallelComputationwithMult-iCoreSystem
ZHUGe-jun,ZHANGL,iSHENGYun-yao
(ChangzhouInstituteofMechatronicTechnology,Changzhou213164,China)
Abstract:Thearticleintroducedthechangeofmult-icoreprogrammingenvironment,comparedthevarioustypesofprogramminglan-guageforparallelcomputingsupportcase,andimplementedthedefiniteintegralscalculationbyimposingmult-ithreadtechnology.The
resultindicatesthatmult-ithreadtechnologyhasverygoodvalueinmult-icoreenvironment.Keywords:mult-icore;parallelcomputation;mult-ithread
(责任编辑 陈晓润)