并行计算——寻找并发性 (功能分解)

我们使用下面的框图来说明怎样寻找我们希望的并发性:

我们使用模式进行分解:

1、分解模式:存在两种分解模式,任务分解和数据分解。使用分解模式将问题分解为多个能够并行的小片段。
2、相关性分析模式:这一组包括3种模式,用于分组任务和分析任务间的相关性:分组任务、排序任务和数据共享。通常,模式是以这种顺序被应用。但是,实际上常常需要重新应用某一个模式,或者甚至可能需要重新使用分解模式。
3、设计评估模式:这个设计中的最后一个模式用于指导算法设计者分析已经完成的工作,然后再转向“算法结构”空间中的模式。这种模式非常重要,因为最好的设计常常不是第一次就能发现的,越早的识别出设计缺陷,就能越容易地更正它们。通常,使用设计中的模式是一个反复的过程。

使用分解模式

我们的分解考虑发生在两个维度之内:

1、任务分解维度:将问题看作是一个指令流,指令流中的指令可以被分解为多个成为任务的序列,所有的任务能够同时执行。为了使计算能够高效地执行,组成一个任务的操作应该尽量独立于其他任务的操作。

2、数据分解维度:集中于分析任务所需要的数据,分析如何将数据分解为多个不同的块。仅当数据块能够被相对独立的操作的时候,与数据块相关的操作才能够高效的执行。

虽然它们两个维度之间有些许“交融”的地方,但是作为一个模式的思考方式,我们从一个独立的角度看问题会容易一些。

任务分解模式

问题:如何将一个问题分解为多个能够并行执行的任务?

背景:
每一个并行算法的出发点都说一样的,即很好的理解所要求解的问题。程序言必须了解问题的哪些部分是计算密集的部分、关键数据结构,以及随着问题的展开,如何使用数据。

下一步是定义组成问题的任务和任务中所隐含的数据分解。通常每一个并行算法包含一个能够并行执行的任务集合。主要的挑战是寻找这些任务,并将其构造成为一个算法。使这些任务能够并行的运行。

在一些情况下,问题将能够很自然的分解为一个独立的(或接近于独立的)任务的集合,并且很容易的开始一个基于任务的分解。在其他情况中,任务的分离可能是非常困难的,因此较好的切入点是数据的分解。至于哪一种方法最好,没有一个统一的标准,通常需要开发者自己思考的时候同时思考两个方式。

面临的问题:
主要问题在于:灵活性、效率和简单性

1、灵活性:设计中的灵活性将使得它能够适应不同的实现需求。例如,在设计的时候,限定选择一个单计算机系统或者编程模型,通常就是一个很糟糕的想法。

2、效率:一个并行程序仅当它能够随着并行计算机的尺度高效的进行伸缩时(减少运行时间或者存储器消耗),才是有用的。对于一个任务分解,这意味着我们需要足够的任务以保持所有的执行单元(处理单元)的繁忙程度,每一个任务具有足够的工作以补偿管理相关性所带来的开销。但是,效率的驱动可能导致缺乏灵活性的复杂分解。

3、简单性:任务的分解需要足够的复杂以完成工作,但是也需要足够的简单,以简化程序调试和维护。

解决方案

一个高效的任务分解的关键在于确保任务充分的独立,以使得管理相关性仅占用程序所有执行时间的一小部分。确保任务的执行能够均匀的分配在所有处理单元上,也是非常重要的(负载平衡问题)。

在一个理想的世界中,编译器会为我们做这一切,帮助我们寻找任务。遗憾的是,这些从来都不会发生。取而代之的是,人们通常必须根据问题和所需要的代码的知识手工完成。在某些情况下,可能需要将问题构造为另一种形式,以揭示相对独立的任务。

对于基于任务的分解,我们将问题看作截然不同的任务的一个集合,并特别注意:

1、解决问题所采取的行动中(具有足够的行动以保持目标机器上的处理元素繁忙吗?)
2、这些行动是截然不同的而且相对独立的吗?

我们应该尽可能的分解任务,这里“过犹不及”就不是那么的正确了,合并问题的消耗要小于分解问题。

我们可以从很多地方找到任务:

1、在某些情况下,每一个任务对应于一个函数的不同调用。为每一个函数调用定义一个任务有时候称为功能分解。

2、另一个寻找任务的地方位于一个算法内循环的不同迭代中。如果一个循环的每一层迭代是独立的,并且具有足够的迭代,则基于任务的分解能够很好的起作用,将每一层的迭代映射到一个任务。这种类型的基于任务的分解有时候称为循环分离(loop-splitting)。

3、任务在数据驱动的分解中也起着重要的作用。在这种情况下,大数据结构被分解,每一个处理单元并发的更新了数据结构的不同块。在这种情况下,任务是在每一个数据块上的更新工作。

另外也需要注意“面临的问题”部分中出现的问题:

1、灵活性:设计在产生任务数目方面需要具备灵活性。通常这通过适当的尺度参数化任务的数目和大小来完成。这将使得设计能够适应多种具有不同处理器数量的并行计算机。

2、效率:在任务分解中,需要考虑两种主要的效率问题。第一,每个任务必须包含足够的工作,以补偿创建任务和处理它们的相关性所带来的开销;第二,任务的数目应该足够大,使得所有的处理单元在整个计算周期内保持繁忙,并做有意义的事情。

3、简单性:定义任务的方式应使得调试和维护简单。如果可能,所定义的任务应当可以重新使用解决相关的问题的现有串行程序的代码。

下一部分我们将介绍一下数据分解。

  • 1
    点赞
  • 1
    收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:大白 设计师:CSDN官方博客 返回首页
评论 1
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值