关于作业通信的进一步说明
通信作业中的任务数
尽管您只为一个通信作业创建了一个任务,但系统会为运行该作业的每个工作单元复制此任务。例如,如果一个通信作业在四个工作单元上运行,则该作业的 Tasks 属性包含四个任务对象。作业的 Tasks 属性中的第一个任务对应于 spmdIndex 为 1 的工作单元所运行的任务,依此类推,这样任务对象的 ID 属性和运行该任务的工作单元的 spmdIndex 具有相同的值。因此,fetchOutputs 函数返回的结果序列与 spmdIndex 的值以及作业的 Tasks 属性中的任务顺序相对应。
避免死锁和其他依赖性错误
由于在一个工作单元中运行的用于通信作业的代码可能会阻止执行,直到另一个工作单元上执行相应的代码为止,因此在通信作业中存在发生死锁的可能性。这种情况最有可能发生在工作单元之间传输数据时,或者使代码依赖于 if 语句中的 spmdIndex 时。一些示例说明了常见的陷阱。
假设您有一个共存分布式数组 D,并且您想使用 gather 函数在单个工作单元的工作区中组装整个数组。
if spmdIndex == 1
assembled = gather(D);
end失败的原因是因为 gather 函数需要在数组分布的所有工作单元之间进行通信。当 if 语句将执行限制到单个工作单元时,执行该函数所需的其他工作单元将不会执行该语句。或者,您可以使用 gather 本身将数据收集到单个工作单元的工作区中:assembled = gather(D, 1)。
在另一个示例中,假设您想要将数据从每个工作单元传输到右边的下一个工作单元(定义为下一个更高的 spmdIndex)。首先,您要为每个工作单元定义左边和右边的工作单元是什么。
from_worker_left = mod(spmdIndex - 2, spmdSize) + 1; to_worker_right = mod(spmdIndex, spmdSize) + 1;
然后尝试在环周围传递数据。
spmdSend (outdata, to_worker_right); indata = spmdReceive(from_worker_left);
该代码可能失败的原因是,根据被传输数据的大小,spmdSend 函数可能会阻止工作单元中的执行,直到相应的接收工作单元执行其 spmdReceive 函数。在这种情况下,所有工作单元都试图同时发送,并且没有一个工作单元尝试接收,而 spmdSend 会阻止它们。换句话说,没有任何一个工作单元能够得到它们的 spmdReceive 语句,因为它们都被阻止在 spmdSend 语句处。为了避免这个特殊问题,您可以使用 spmdSendReceive 函数。