【问题标题】:Organizing a task-based scientific computation组织基于任务的科学计算
【发布时间】:2011-07-20 12:27:59
【问题描述】:

我有一个计算代数任务需要编写代码。问题被分解为定义明确的个体任务,这些任务自然形成树——任务本质上是组合的,因此有一个主要任务需要少量的子计算来获得结果。那些子计算有子子计算等等。每个计算只取决于树中它下面的计算(假设根节点是顶部)。分支机构之间无需进行数据共享。在较低级别,子任务的数量可能非常大。

我之前以函数方式对其进行了编码,根据需要调用函数并将所有内容存储在 RAM 中。这是一种糟糕的方法,但我当时更关心的是理论。

出于各种原因,我打算用 C++ 重写代码。我有几个要求:

  • Checkpointing:计算需要很长时间,所以我需要能够随时停止并稍后恢复。
  • 将单个任务分离为对象:这有助于我很好地掌握我在计算中的位置,并提供了一种通过序列化进行检查点的简洁方法。
  • 多线程:任务显然是令人尴尬的并行,所以利用它会很巧妙。我可能想为此使用 Boost 线程。

我想就如何实际实施这样的系统提出建议。我想到的方法:

  1. 以简单堆栈的形式实施任务。当您遇到需要完成子计算的任务时,它会检查它是否具有所需的所有子计算。如果没有,它会创建子任务并将它们扔到堆栈上。如果是,则计算其结果并将自己从堆栈中弹出。
  2. 将任务存储为树并执行类似于深度优先访问者模式的操作。这将在开始时创建所有任务,然后计算将遍历树。

这些似乎不太正确,因为较低级别的问题需要大量子任务。我想我可以在这个级别以迭代器的方式来处理它。

我觉得我想多了,而且已经有一种简单、成熟的方法来做这样的事情。有吗?


技术细节以防万一:

  • 任务树有 5 个级别。
  • 对于所有级别,树的分支因子都非常小(例如,在 2 和 5 之间),但最低的级别为几百万。
  • 每个单独的任务只需要存储几十个字节的结果。我不介意尽可能多地使用磁盘,只要它不会影响性能。
  • 为了调试,我必须能够调用/重新计算任何单个任务。
  • 所有计算都是离散数学:整数、多项式和组的计算。根本没有浮点数。

【问题讨论】:

  • 让它“可分发”有意义吗? IE。设计每个计算,以便它可以由主程序“就地”执行,可能在一个线程中,但也可以分布在更多节点上,有点像 SETI@home?
  • 不是一个答案,只是一个想法,但这似乎让人想起像“make”这样的构建工具在跟踪目标之间的依赖关系时所做的事情。在这种情况下,检查点由文件系统自动处理。 Gnu make 当然可以选择使用多个线程。可能值得研究一下您是否可以从他们的做法中学到任何东西。
  • 我想对于第二个从底部的任务分发它是有道理的(包括几百万个子任务)。所有其他任务都需要很少的时间,所以不值得。除了我自己的电脑之外,我也不希望能够访问更多的东西。

标签: c++ design-patterns architecture combinatorics


【解决方案1】:

有一个主要任务需要少量的子计算才能得到结果。那些子计算有子子计算等等。每个计算只取决于树中它下面的计算(假设根节点是顶部)。分支机构之间无需进行数据共享。在较低的级别,子任务的数量可能非常大......等等等等,多线程等等。

如果我错了,请纠正我,但在我看来,您正在准确地描述 map-reduce 算法。

只需阅读 wikipedia 上关于 map-reduce 的说法:

“映射”步骤:主节点获取输入,将其划分为更小的子问题,并将这些子问题分发给工作节点。工作节点可能会再次执行此操作,从而形成多级树结构。工作节点处理较小的问题,并将答案传回其主节点。

“减少”步骤:然后主节点获取所有子问题的答案,并以某种方式将它们组合以获得输出——它最初试图解决的问题的答案。

使用现有的 mapreduce 框架可以为您节省大量时间。

我只是在谷歌上搜索“map reduce C++”并开始得到结果,尤其是 boost http://www.craighenderson.co.uk/mapreduce/

【讨论】:

  • 您查看您的链接了吗? “注意:这个库不是 Boost 库的一部分。它在 Boost 存储库中已经存在了很多年,我将库开发到今天的地步。Boost 社区对采用 MapReduce 作为一个官方库,所以我把它从他们的 Subversion 存储库移到了 GitHub 上。我希望这将使项目更易于访问。”
  • @Offirmo:通用的 MapReduce 框架绝对符合要求(天哪!应该想到这一点)。但是,根据框架的不同,实现细节需要大量的工作。提到的库看起来很整洁,但文档很少。
  • @David 不,我没有查看链接,也没有认可它。现在由 Brett 使用 google 并在互联网超市中选择合适的 map-reduce 框架。享受吧!
【解决方案2】:

这些似乎不太正确,因为较低级别的问题需要大量子任务。我想我可以在这个级别以迭代器的方式来处理它。

您绝对不想要数百万个 CPU 密集型线程。您最多需要 N 个 CPU 绑定线程,其中 N 是 CPU 数量与机器上每个 CPU 的内核数量的乘积。超过 N 一点点,你就会放慢速度。超过 N 很多,你就会放慢速度。机器几乎将所有时间都用于在上下文中交换线程,只花费很少的时间来执行线程本身。超过 N 很多,你很可能会崩溃你的机器(或达到线程的一些限制)。如果您想一次处理大量(以及大量)并行任务,则需要使用多台机器或使用显卡。

【讨论】:

  • 当然。我在想会有固定数量的并发线程(等于你提到的 N)。每个人都会抓住可用的任务并投入其中。完成后,线程将保持活动状态,但会处理新任务。我不会为每个任务创建/销毁线程,因为我不应该支付开销。
猜你喜欢
  • 1970-01-01
  • 2017-07-07
  • 1970-01-01
  • 1970-01-01
  • 2013-01-29
  • 2014-09-16
  • 1970-01-01
  • 1970-01-01
  • 2013-08-22
相关资源
最近更新 更多