zz - TBB/OpenMP/本地线程

转载 2010年06月01日 11:04:00

选择英特尔® 线程构建模块?OpenMP?还是本地线程?


 


如果是您,您会选择哪一种 API 来为您的软件应用引入线程?我们是否又可找到一把万能的钥匙呢?本文就将顺着这些疑问,带您全面了解开发人员在进行选择时需要考虑的各种问题,并着重分析开发环境和并行模式的复杂程度,以便您了解这些 API 在您的软件中共存时会带来怎样的功能和处理能力差异。



开发环境

繁简程度考虑因素

与 OpenMP 或英特尔® 线程构建模块(TBB)相比,本地线程编程模式采用了更为复杂的代码,因而其维护工作的难度也就相对较大。这样,您在适当的情况下,不妨使用英特尔® TBB 或 OpenMP,利用这些 API 的优势帮您创建并管理线程池:自动实现线程同步,自动完成排程。



编程语言、编译器支持及自由迁移考虑因素

如果您的代码采用 C++ 编写,那么,英特尔® TBB 无疑将是最佳选择。这是因为,英特尔® TBB 大量使用了 C++ 模板和用户自定义类型,所以特别适宜对象导向程度较高的代码。如果代码采用 C 或 FORTRAN 语言编写,那么,OpenMP 则可能是最为适合的解决方案。因为它相比英特尔® TBB,更适用于结构型代码风格和简单代码,并且代码开销也相对较低。但是,即便采用 C++ 代码,如果算法是以阵列处理活动为主导,则在编码复杂程度方面,OpenMP 还是要优于 TBB。本地线程编程模式的复杂程度与 C 和 C++ 语言相类。但是,由于线程工作必须表述为一个函数,因此,采用本地线程进行的编程,如采用 C 语言等编程语言则会显得更加自然灵活。而对于那些对象导向程度较高的 C++ 程序来说,由于本地线程无法清晰表达对象,因此如使用该类线程则可能破坏原有的风格和设计。

此外,英特尔® TBB 和本地线程无需编译器支持,而 OpenMP 却需要。并且在使用 OpenMP 时,您还需要采用一个可识别 OpenMP 范式的编译器进行编译。但是英特尔® C++ 和 Fortran 编译器均支持 OpenMP。近来,众多其他厂商生产的其它类型的 C++ 和 Fortran 编译器中也都或多或少的添加了一些 OpenMP 支持功能。

基于 OpenMP 和英特尔® TBB 的解决方案可在 Windows、Linux、Mac OS X、Solaris 以及众多其它操作系统之间自如迁移。如将基于本地线程的解决方案迁移到另外一种操作系统上,通常需要修改代码,这就势必会引入初始开发/调试工作,从而加重了维护负担。尤其是您希望在 Windows (通常使用 Windows 线程)和 UNIX (通常使用 POSIX 线程)之间实现迁移时,这一影响就会更加突出。

 

并行编程模式的复杂程度

事实上,API 的选用主要还是取决于您想对哪些代码实现并行。如果您的并行模式主要用于内建类型的有界循环(bounded loop),或是平面的 do-loop 中央循环,那么,建议您最好采用 OpenMP。

TBB 采用泛型编程,因此,如果您需要定制迭代空间或复杂归约运算,那么,它的循环并行化模式则能帮您“应付自如”。当然,如果您需要将并行化运用到循环以外的范围,您亦可使用 TBB。这是因为它可为并行 while-loop 循环、数据流管线模式、并行排序和并行前缀算法提供泛型并行模式。

OpenMP 支持嵌套并行,并可采用本地线程执行。但是,如果使用这两种线程 API,则极易造成资源过度利用。TBB 在此方面技高一筹,它自然支持嵌套和递归并行,并且其任务调度程序的“任务偷窃技巧(task stealing technique)”还能帮忙管理一定数量的线程。凭借这一先进技术以及任务调度程序的动态负载均衡算法,TBB 可调度所有处理器内核全力处理有益工作,既可有效避免过度使用线程(软件线程过多将会带来不必要的开销),又可顺利解决线程用力不足的难题(软件线程太少意味着您未充分利用所提供多个内核的资源)。

TBB 和 OpenMP 还专门增添了用于提供重点关注可扩展性数据并行分解的构造函数,以期通过线程化提升系统的性能和可扩展性。这些函数在处理计算密集型工作方面,对我们极有帮助。而本地线程与之相比,在实现并行和卓越的可扩展性方面却略胜一筹。如果您使用本地线程执行 TBB 中已经提供的模式/算法,则极有可能引发数据竞争和死锁等线程错误。当然,本地线程也不是“一无是处”,它在基于事件或 I/O 的线程化中还是“身手不凡”的。

功能比较

 

英特尔® TBB

OpenMP

本地线程

任务级并行

+

+

-

数据分解支持

+

+

-

复杂并行模式(非循环)

+

-

-

广泛应用泛型并行模式

+

-

-

可扩展嵌套并行支持

+

-

-

内建负载均衡

+

+

-

亲和支持(Affinity support)

-

+

+

静态排程

-

+

-

并发数据结构

+

-

-

可扩展内存分配算符

+

-

-

以I/O为主导的任务

-

-

+

用户级同步基元

+

+

-

无需编译器支持

+

-

+

跨 OS 支持

+

+

-

 

上文我们提到在选择何种线程化 API 时,需要考虑开发环境及并行模式复杂程度相关因素。但是如果在某种情况下,您只能选择 TBB 或 OpenMP 中的一个时,您该怎么办?答案其实很简单,这时我们就需要考虑 API 自身所具备的功能了。如果您需要的功能仅 OpenMP 具备,那就选择 OpenMP。同理,如果您需要的功能仅 TBB 具备,那就使用 TBB。如果您需要的功能 TBB 和 OpenMP 均具备,此时,我们建议您考虑维护成本:尽管TBB 和 OpenMP 均可跨操作系统迁移,但它们在编程风格方面还是各有侧重,且对开发环境也有不同的要求。TBB 和 OpenMP 这两种 API 可以共存,但也可能出现性能问题(详见“共存”章节论述)。因此,建议您最好选择能够满足您所有需求的模式。如果您正在进行一项新的设计方案,并计划使用 C++ 语言编程,那么 TBB 应该是个不错的选择:因为它支持预期并行的增加,允许执行更多并行运算,且无需创建那些可能导致过度使用的不必要的线程。

当然,预期在同一算法中,基于英特尔® TBB、OpenMP 和本地线程的解决方案的执行效果还是相差无几的(提供同等水平的性能)。但是,低水平本地线程 API 必然会产生大量附加编码成本,因此,相比而言,TBB 和 OpenMP 更可取一些。

 

共存

TBB、OpenMP 和本地线程可以共同使用,三者之间也可实现互操作。但是,由于 TBB 和 OpenMP 运行时库创建独立的线程池,且在缺省状态下,每个线程池还会创建多条线程来匹配内核数量,这就可能导致线程过量的问题。此外,两组 worker 线程还均用于计算密集型工作,这也会不可避免地造成线程过量问题。因此,我们建议您利用英特尔® TBB 来重写 OpenMP 代码(如果 TBB 符合应用程序设计标准)。这样,OpenMP 工作就不会与 TBB 活动交迭,线程过量也就自然而然地解决了。

鉴于英特尔® TBB 任务调度程序未采用公平和优先机制。因此,不推荐您使用英特尔® TBB 来处理 I/O 有界任务(bound task)。这时,本地线程是您最佳选择,而且它还可与英特尔® TBB 组件共存。

 

结论

线程化方法的选择是并行应用程序设计流程中的重要环节。没有一款解决方案能够满足所有需求、适用于各种环境。它们有些需要编译器支持,有些不可跨 OS 迁移,或者未采用专门的线程化分析工具。我们设计的英特尔® 线程构建模块拥有丰富的结构框架,涵盖了众多常用并行设计模式,能够通过提供并发数据容器、同步基元、并行算法以及可扩展内存分配算符,帮助开发人员更快地创建可扩展程序。

更多参考信息 

1. 《英特尔® 线程构建模块:采用 C++ 实现多核处理器并行化》,James Reinders,O'Reilly Media,2007 年,ISBN 0596514808。
2. 开源项目页面:http://www.threadingbuildingblocks.org  
3. 产品页面:http://www.intel.com/software/products/tbb  
4. Dr. Dobb 的网络研讨会“英特尔® 线程构建模块:面向多核的可扩展编程”:http://www.cmpnetseminars.com/TSG/?K=3TW6&Q=417  
5. “使用英特尔® 线程构建模块的泛型并行算法,揭开可扩展并行编程的神秘面纱”:http://www.devx.com/cplus/Article/32935  
6. “使用英特尔® 线程构建模块的并发容器,实现安全、可扩展的并行编程”:http://www.devx.com/cplus/Article/33334  
7. 产品介绍:英特尔® 线程构建模块:http://www.devx.com/go-parallel/Article/33270  
8. “并发革命”,Herb Sutter,Dr. Dobb’s 1/19/2005:http://www.ddj.com/dept/cpp/184401916  

TBB/OpenMP/raw thread三种并发编程的取舍分析

繁简程度考虑因素 与 OpenMP 或英特尔® 线程构建模块(TBB)相比,本地线程编程模式采用了更为复杂的代码,因而其维护工作的难度也就相对较大。这样,您在适当的情况下,不妨使用英特尔® TBB...
  • yuwei629
  • yuwei629
  • 2013-07-11 16:52:31
  • 2930

关于高性能计算(并行计算)的知识记录汇总(OpenMP、OpenCL、CUDA、TBB)

关于高性能计算的知识记录汇总       原文来自:http://blog.sina.com.cn/s/blog_6b99cdb50101inv5.html       看了这个文章,对我的知识面有...
  • KayChanGEEK
  • KayChanGEEK
  • 2017-11-13 10:14:29
  • 325

linux下Intel TBB、 Open MPI、OpenMP

Linux下TBB安装 1) 到官方网站下载最新的TBB源程序。       https://www.threadingbuildingblocks.org/ 2) 建立安装目录,这个目录就是用来...
  • feng1072218457
  • feng1072218457
  • 2016-04-30 23:46:53
  • 1162

认识OpenMP优点

进入多核时代后,必须使用多线程编写程序才能让各个 CPU 核得到利用。在单核时代,通常使用操作系统提供的 API 来创建线程,然而,在多核系统中,情况发生了很大的变化, 如果仍然使用操作系统 API ...
  • Linear_Luo
  • Linear_Luo
  • 2016-09-23 22:19:14
  • 906

用openMP进行并行加速

最近在看多核编程。简单来说,由于现在电脑CPU一般都有两个核,4核与8核的CPU也逐渐走入了寻常百姓家,传统的单线程编程方式难以发挥多核CPU的强大功能,于是多核编程应运而生。按照我的理解,多核编程可...
  • lanbing510
  • lanbing510
  • 2013-12-04 01:03:13
  • 2553

openMP的一点使用经验【非原创】

按照百科上说的,针对于openmp的编程,最简单的就是在开头加个#include,然后在后面的for上加一行#pragma omp parallel for即可,下面的是较为详细的介绍了openmp的...
  • shouhuxianjian
  • shouhuxianjian
  • 2015-06-22 12:32:16
  • 1291

OpenCV中OpenMP的使用

vs2010中调用openMP,并添加头文件#include   代码来源: 作者:gnuhpc 出处:http://www.cnblogs.com/gnuhpc/   #include "std...
  • wangyaninglm
  • wangyaninglm
  • 2015-03-02 17:04:00
  • 4723

OpenMP学习

http://openmp.org/wp/ 传统的单线程编程方式难以发挥多核CPU的强大功能,于是多核编程应运而生。多核编程可以认为是对多核环境下编程做了一些多线程抽象,提供一些简单的API,使得用...
  • CHS007chs
  • CHS007chs
  • 2014-12-10 16:50:23
  • 1069

编译源码 - 【OpenCV 3.x + TBB + IPP + OpenMP + CUDA 6.5(更新cuda 8.0)】- 【win7x64 + vs2012】

1、CMake 先安装好TBB,到官网下载,配置系统环境PATH(添加bin目录); 勾选“WITH_TBB”、“WITH_IPP”、“WITH_CUDA”、“WITH_OPENMP”,cuda下面还...
  • Kelvin_Yan
  • Kelvin_Yan
  • 2015-09-24 16:58:33
  • 3697
收藏助手
不良信息举报
您举报文章:zz - TBB/OpenMP/本地线程
举报原因:
原因补充:

(最多只允许输入30个字)