一、并行编程
多线程和多进程编程,在早期一般是并发编程,现在基本是并行编程的基础。或者干脆就叫并行编程也没有什么可纠结的。但实际上并发编程和并行编程还是有着很大的不同。在前面的“多核和多CPU编程”系列中,已经对并发和并行的概念以及其不同进行了较深入的分析。如果有不太明白的,可以移步那个系列的文章。
这里之所以再次谈起,主要是在写线程的过程中,其实并发和并行往往是不分家的。一些常见的高并发处理的场景中,为了更好的利用多核和多CPU的优势,往往会引入一些并行库进行处理,目的只有一个,就是最大程度的压榨CPU的潜力。
可是,并行库的引入有利也有弊。最典型的就是一旦出现了线程间的问题,查找和定位问题就成了一个非常头疼的故事。这个就需要非常有经验的开发者不断的进行各种分析和调度,甚至可以深入到库内部进行查看问题的场景的发生路径(前提是开源库)。
二、并行库和应用
这里不对并行的模式进行分析,只是介绍一下目前比较常见的并行库:
1、OpenMp
这个可能是最常见的并行库了,估计一般写过并行程序的开发者或多或少都接触过。简单,易用。但功能上有一些限制,比如对非共享内存就有点不适应。
2、Intel TBB
TBB的应用因为有Intel背书,应用还是比较广泛的,类似于图的调度方式,更加灵活方便。抽象做的不错。但可能和硬件关联较强,毕竟谁家父母不喜欢自己家的孩子。
3、STL和Boost提供的并行库
其实在这类库提供的并行方式大多是基于函数接口方面的,更方便组合使用。特别是在c++11后提供了更多的并行算法如std::copy,std::find等等。
4、CUDA和OpenCL
这两种比较偏向于GPU,当然OpenCL也支持CPU、FPGA等。OpenCL做为一种跨平台的并行框架,支持的力度还需要加强。
其它并行库还有,但多是比较专业了。
并行库的应用,一般是对处理效率有着比较强的要求下才应用的。最常见的一般在大数据处理分析、图像处理、音视频处理以及一些科学计算等计算密集型与IO密集型紧密协调的情况下较多。
举一个最常见的例子,需要对十张图像进行灰度、编码、压缩等多道工序进行处理。那么并行库的优势就可以发挥出来。特别是当这个十张图像的大小不一,压缩的算法也要根据不同的情况进行压缩时,那么处理时序就可以乱序(非输入顺序)进行处理。如果最终要求恢复时序,再做时序处理即可,如果不要求,则可以直接吐出结果。那么此时,对线程的处理就已经比较复杂了。那么如果增加到一百张、一千张甚至更多的图像呢?
这样做的结果,理论上讲,单张处理最大的耗费时长即为十张图像总处理的时长。这对于一些图像处理算法,特别现在AI训练时的意义可想而知。
三、例程
这里举一个TBB的例子:
int main(){
int ret = 0;
broadcast_node<int> bNode(g);
graph g;
function_node< int, int > Sqr( g, 2, [](const int &data) {
return data*data;
} );
function_node< int, int > Mul( g, 2, [](const int &data) {
return data*3;
} );
function_node< int, int > Sum( g, 1, [&](const int &data ) -> int {
return ret += v;
} );
make_edge( Sqr, Sum );
make_edge( Mul, Sum );
make_edge( bNode, Sqr );
make_edge( bNode, Mul );
for ( int i = 1; i < 20; ++i ) {
bNode.try_put(i);
}
g.wait_for_all();
std::cout << "result is " << ret << std::endl;
return 0;
}
使用这种抽象的图方式来组织并行线程间的数据流动非常有益,特别是在这些数据节点传送时,需要动态切换的情况下,可以达到设计上的开闭原则而又不失灵活性。在Github上有不少使用TBB进行更高层的抽象应用的例子,推荐大家去学习一下。这些抽象的思想也可以应用在自己的多线程的应用上。
四、总结
古人说:“工欲善其事,必先利其器”,牛顿说要站在巨人的肩膀上,道理都是想通的。程序的设计开发也是如此,前人做过了很多非常有益的工作,后来者不必非再重复造一个轮子。但说这话得有一个前提,你得知道怎么造轮子,并且明白其内部的猫腻。
学以致用,用而后思。不断总结推进自己的编程水平和提高自己的编程思想,这才是王道。
并行编程并不是本系列文章的目的,这里把并行编程的相关进行基础的分析介绍,主要目的是让开发者明白,所谓并行框架的基石,仍然是多线(进)程编程。只要掌握了这些基础,那么在后期的学习和应用中,就会游刃有余!