【问题标题】:Message Passing Arbitrary Object Graphs?消息传递任意对象图?
【发布时间】:2011-01-21 16:24:04
【问题描述】:

我希望在 Beowulf 集群中并行化一些代码,这样所涉及的 CPU 就不会共享地址空间。我想在外循环中并行化一个函数调用。函数调用没有任何“重要”的副作用(尽管它们确实使用随机数生成器、分配内存等)。

我查看了像 MPI 这样的库,我看到的问题是它们似乎使得在节点之间传递复杂的对象图变得非常重要。我的函数的输入是指向一个非常复杂的对象图的 this 指针。我的函数的返回类型是另一个复杂的对象图。

在与语言无关的级别(我正在使用 D 编程语言,我几乎可以肯定这里没有可用的罐装解决方案,但我愿意创建一个),是否有一种“典型”的方式处理跨节点传递复杂状态的问题?理想情况下,我希望完全抽象出如何复制状态的详细信息,并使调用看起来几乎像正常的函数调用。我不在乎通过网络复制这么多状态不是特别有效,因为所讨论的并行级别是如此粗粒度,以至于它可能无关紧要。

编辑:如果没有简单的方法来传递复杂的状态,那么通常如何使用消息传递?在我看来,任何涉及通过网络复制数据的事情都需要粗粒度的并行性,但粗粒度的并行性通常需要传递复杂的状态,以便可以在一个工作单元中完成大量工作。

【问题讨论】:

    标签: multithreading language-agnostic networking parallel-processing mpi


    【解决方案1】:

    我做了相当多的 MPI 编程,但我不知道在进程之间传递复杂状态(如您所描述的)的任何典型方式。这是我一直在思考你的问题的方式,它可能与你自己的想法相符......

    我推测您的复杂对象图在内存中由数据块和指向其他数据块的指针表示——这是图的一种常见实现。如何最好地将这些 COG 中的一个(创造一个缩写)从一个进程的地址空间移动到另一个进程的地址空间?就指针是内存地址而言,一个地址空间中的指针在另一个地址空间中没有用,因此您必须将其转换为某种中性形式以进行传输(我认为?)。

    因此,要发送 COG,必须将其放入某种形式,以便接收进程可以在其自己的地址空间中构建图的本地版本,其中指针指向本地内存地址。您是否曾经将这些 COG 写入文件?如果是这样,您已经有了一个可以运输的表格。我不建议这样做,但您甚至可以使用文件在进程之间进行通信——这可能比 D 和 MPI 的组合更容易处理。你的选择!

    如果您没有 COG 的文件表单,您能否轻松地将它们表示为邻接矩阵或列表?换句话说,制定你自己的交通表示?

    如果您可以在进程之间传递 COG 而无需将其从基于指针的结构转换为更静态的结构(如数组或记录),我会感到非常惊讶(但很高兴得知)。

    编辑,以响应 OP 的编辑。 MPI 确实提供了传递复杂状态的简单方法,前提是复杂状态表示为值而不是指针。您可以在内部或自定义 MPI 数据类型中传递复杂状态;正如其他答案之一向您展示的那样,这些都是灵活且有能力的。如果我们的程序不能以 MPI 自定义数据类型可以处理的形式保持复杂状态,则您必须编写函数来打包/解包为消息友好的表示形式。如果你能做到这一点,那么你的消息调用将(在大多数情况下)看起来像函数调用。

    关于复杂状态和并行性的粒度问题,我不确定我是否完全关注你。我们(如果你愿意,也可以把你自己包括在这个全面的概括中)通常求助于 MPI 编程,因为我们无法从单个处理器中获得足够的性能,我们知道我们会因等待​​而延迟计算而付出代价对于通信,我们努力将这种惩罚最小化,但最终我们接受惩罚作为并行化的成本。当然,有些工作太小或太短而无法从并行化中受益,但我们(即并行计算主义者)所做的很多事情都太大且运行时间太长而无法避免并行化

    【讨论】:

      【解决方案2】:

      您可以使用自定义 MPI 数据类型做一些奇妙的事情。我目前正在从事一个项目,其中几个 MPI 进程正在跟踪一个虚拟空间中的粒子,当粒子从一个进程的区域跨越到另一个进程的区域时,它们的数据(位置/速度/大小/等)必须是通过网络发送。

      我实现的方法如下:

      1) 对于单个粒子,所有进程共享一个 MPI Struct 数据类型,该数据类型包含其所有相关属性,以及它们在内存中相对于粒子对象的基地址的位移。

      2) 在发送时,该进程遍历它存储粒子的任何数据结构,记下每个需要发送的内存地址,然后构建一个 Hindexed 数据类型,其中每个块的长度为 1 (上面提到的粒子数据类型)并从之前记下的内存地址开始。发送 1 个结果类型的对象将以类型安全的方式通过网络发送所有必要的数据。

      3) 在接收端,事情有点棘手。接收进程首先将“空白”粒子插入到自己的数据结构中:“空白”意味着将从其他进程接收到的所有属性都初始化为某个默认值。记下新插入粒子的内存地址,并从这些地址创建类似于发送者的数据类型。将发件人的消息作为这种类型的单个对象接收会自动以类型安全的方式将所有数据解包到所有正确的位置。

      这个例子更简单,因为粒子之间没有关系(就像图的节点之间一样),但是您可以以类似的方式传输该数据。

      如果上面的描述不清楚,我可以贴出实现它的C++代码。

      【讨论】:

        【解决方案3】:

        我不确定我是否正确理解了这个问题,如果我的答案有误,请原谅我。据我了解,您想使用 MPI 发送非 POD 数据类型。

        可以做到这一点的库是Boost.MPI。它使用序列化库来发送甚至非常复杂的数据结构。但是有一个问题:如果您使用 Boost.Serialize 尚不知道的复杂结构,则必须自己提供代码来序列化数据。

        我相信消息传递通常用于传输 POD 数据类型。

        我不允许发布更多链接,所以我想包括以下内容:

        POD 说明:www.fnal.gov/docs/working-groups/fpcltf/Pkg/ISOcxx/doc/POD.html

        序列化库:www.boost.org/libs/serialization/doc

        【讨论】:

          【解决方案4】:

          这取决于您的数据组织。如果您在对象内部使用指针或自动内存,这将很困难。如果您可以将对象组织成在内存中是连续的,您有两种选择:将内存作为字节发送,将其转换回接收器上的对象类型或为您的对象定义 mpi 派生类型。但是,如果您使用继承,由于对象在内存中的布局方式,事情会变得复杂。

          我不知道你的问题,但如果你手动管理内存,也许可以看看 ARMCI。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2017-06-05
            • 1970-01-01
            • 1970-01-01
            • 2014-01-07
            • 1970-01-01
            • 2015-11-27
            • 2021-08-05
            • 2018-09-11
            相关资源
            最近更新 更多