最近我一直在写关于并行计算和编程的文章,我注意到在并行计算方面有很多模式。我注意到微软已经发布了一个库,名为Parallel Patterns Library,随同Microsoft Visual C++ 2010社区技术预览版一起发布。我想知道你使用过哪些常见的并行编程模式,并且这些模式值得记住吗?你是否有任何习惯用语和模式,在使用C++编写并行程序时不断出现?
最近我一直在写关于并行计算和编程的文章,我注意到在并行计算方面有很多模式。我注意到微软已经发布了一个库,名为Parallel Patterns Library,随同Microsoft Visual C++ 2010社区技术预览版一起发布。我想知道你使用过哪些常见的并行编程模式,并且这些模式值得记住吗?你是否有任何习惯用语和模式,在使用C++编写并行程序时不断出现?
模式:
生产者/消费者
循环并行
重绘线程
主事件线程
工作组
首先,您需要在共享内存计算和共享无内容计算之间进行选择。共享内存较为简单,但扩展性不佳——如果您:
a)拥有一个集群而非多处理器系统;或者
b)拥有许多 CPU(例如,大于 60),并且存在高度不均匀的内存
则应使用共享无内容。
对于共享内存,常见解决方案是使用线程;虽然概念易懂,在 API 中易于使用,但难以调试。
对于共享无内容,您需要使用某种形式的消息传递。在高性能计算中,MPI 已成为消息中间件。
此外,您还需要设计并行活动的架构。最常见的方法(因为易于理解)是 farmer-worker 模式(又称主从模式)。
并行执行模式
确定性模式的结构化并行编程是一种高级方法,主要基于一组经常使用的并行执行模式,通常称为算法骨架或并行构造。这些模式抽象了程序描述并隐藏了程序员所需的低级多线程细节和许多与并行相关的复杂性。
这些可重用的模式自动化许多并行范例相关的例行程序,例如同步、通信、数据分区或任务调度,并在内部处理它们。这种高级方法试图通过更抽象和更容易表达并行性的方式来尝试传统的低级线程锁模型,并专注于生产力和可编程性而不是性能。
有许多常用的模式,例如:Map-Reduce、Fork-Join、Pipeline或Parallel Loop...
论文
《带确定性模式的结构化并行编程》是一篇讨论这些模式的论文。您还可以查看“MHPM:多尺度混合编程模型:一种灵活的并行化方法”,该论文描述了一个名为XPU的C++实现。
库
XPU是一个基于任务的C++库,由一组可重用的执行模式组成。它允许在单个同质编程模型中表达多种粒度级别的并行性。它易于使用,并说明了使用模式设计并行程序的兴趣。
例如,它允许表达:
任务并行模式:
具有一些特征的简单或分层Fork/Join执行模式,例如自动检测和保护共享数据。
数据并行模式:
可扩展数据分区的并行循环模式。
时间并行模式:
管道执行模式。
auto fut = async([]( ){..some work...} ).then( [](result_of_prev ){...more work} ).then... ;
fut.wait( );
auto semaphore = make_semaphore( num_tasks );
add_task( [&semaphore]( ) {...task1...; semaphore.notify( ); } );
add_task( [&semaphore]( ) {...task2...; semaphore.notify( ); } );
...
add_task( [&semaphore]( ) {...taskN...; semaphore.notify( ); } );
semaphore.wait( );
一些减少通信的技巧包括使用结果数组,以便每个任务不会尝试锁定对象以推送值。通常情况下,稍后减少这些结果可能非常快。
但是,在所有类型的并行性中,缓慢来自于通信。减少它。