这是我在为使用MPI(在C ++中)并行运行的算法设计错误处理时遇到的一些常见问题:
答案 0 :(得分:7)
在理想的世界中,你可以用它们来做你所要求的。 “理想世界”是指您可以选择MPI实现并且能够自己管理它(而不是说服集群所有者为您重新配置它)。异常的最小配置包括: - with-exceptions 标志,可能还有一些。
我最常使用LAM,默认情况下禁用例外。我相信这也是其他实现的默认设置。
它们的工作方式与'vanilla'C ++异常相同。他们确实在并行执行的代码中工作。
在启动代码中的某个时刻,您想要启用它们:
MPI::COMM_WORLD.Set_errhandler ( MPI::ERRORS_THROW_EXCEPTIONS );
(如果您的库未配置为允许例外,这可能是个坏主意 - 根据LAM,行为“未定义”)
然后:
try { /* something that can fail */ }
catch ( MPI::Exception e ) {
cout << "Oops: " << e.Get_error_string() << e.Get_error_code();
MPI::COMM_WORLD.Abort (-1) ;
}
至于做法的好坏,我实在无法说。我没有看到在强化的MPI黑客编写的代码中广泛使用它们,但这可能是因为根据我的经验,代码通常比C ++更多。
错误代码和异常之间的中间地带可能是错误处理程序,简而言之,您可以分配在发生特定错误(由代码指定)时将调用的函数。如果您无法让管理员加入启用例外的情况,这可能是一个选项。
答案 1 :(得分:6)
在MPI代码中,异常与串行代码的作用相同,但如果可能在通信器中的所有进程中都没有引发异常,或者您很容易导致死锁,则必须非常小心。 / p>
MPI_Barrier(comm); /* Or any synchronous call */
if (!rank) throw Exception("early exit on rank=0");
MPI_Barrier(comm); /* rank>0 deadlocks here because rank=0 exited early */
所有错误处理方法都存在此问题,很难从通信器中不一致的错误中恢复。在上面的例子中,您可以执行MPI_Allreduce
,以便所有等级选择相同的分支。
我的首选是调用错误处理程序并将它们传播到堆栈中,因为这会给我提供最有用/最详细的错误消息,并且很容易捕获断点(或者错误处理程序可以将调试器附加到自身并发送它在xterm中的工作站。
答案 2 :(得分:0)
异常在并行执行期间是否有效取决于您的编译器和MPI库实现。如果你想要可移植的行为,我会避免在这种情况下抛出异常。
如果您想了解有关错误的更多详细信息而不仅仅是数字返回码,您当然可以返回和/或传递错误字符串或其他对象(当然在同一进程内或通过MPI)。