Mpi “什么是正确的方法?”;“通知”;没有阻塞的处理器?
假设我有一个非常大的数组,我必须对所有这些东西做一些操作。 如果一个元素的操作失败,我希望停止整个阵列的工作[此工作分布在多个处理器上] 我希望实现这一点,同时将发送/接收的消息数量保持在最低限度。 另外,如果没有必要,我不想阻塞处理器Mpi “什么是正确的方法?”;“通知”;没有阻塞的处理器?,mpi,Mpi,假设我有一个非常大的数组,我必须对所有这些东西做一些操作。 如果一个元素的操作失败,我希望停止整个阵列的工作[此工作分布在多个处理器上] 我希望实现这一点,同时将发送/接收的消息数量保持在最低限度。 另外,如果没有必要,我不想阻塞处理器 如何使用MPI实现这一点?这是我问自己的一个问题,但没有找到任何完全令人满意的答案。。。我想到的唯一一件事(除了MPI_Abort()可以这样做,但有点极端)是创建一个MPI_Win存储一个标志,该标志将由遇到问题的任何进程发出,并由所有进程定期检查,以查看它们
如何使用MPI实现这一点?这是我问自己的一个问题,但没有找到任何完全令人满意的答案。。。我想到的唯一一件事(除了
MPI_Abort()
可以这样做,但有点极端)是创建一个MPI_Win
存储一个标志,该标志将由遇到问题的任何进程发出,并由所有进程定期检查,以查看它们是否可以继续处理。这是使用非阻塞调用完成的,方法与中所述相同
这方面的主要弱点是:
最后,我们需要的是一种定义由MPI调用触发的回调操作的方法,例如
MPI\u Abort()
(基本上用其他操作替换中止操作)。我认为这不存在,但可能我忽略了它。以非阻塞方式导出此全局停止条件的可能策略是依赖于MPI\U测试
脚本
假设每个进程将一个类型为MPI_INT的异步接收与一个给定的标记一起发布到其左秩,以构建一个环。然后开始计算。如果一个列组遇到停止条件,它会将自己的列组发送到正确的列组。同时,每个列组在计算期间使用MPI_Test
检查MPI_Irecv
的完成情况,如果完成,则首先输入一个分支等待消息,然后将接收到的列组传递到右侧,除非右列组等于消息的有效负载(不循环)
这样,分支中的所有进程都可以触发任意恢复操作
复杂性
保留的拓扑是一个环,因为它最大限度地减少了消息数量(n-1),但增加了传播时间。其他拓扑可以保留更多的消息,但空间复杂度较低,例如具有n.ln(n)复杂度的树
实施
像这样的
int rank, size;
MPI_Init(&argc,&argv);
MPI_Comm_rank( MPI_COMM_WORLD, &rank);
MPI_Comm_size( MPI_COMM_WORLD, &size);
int left_rank = (rank==0)?(size-1):(rank-1);
int right_rank = (rank==(size-1))?0:(rank+1)%size;
int stop_cond_rank;
MPI_Request stop_cond_request;
int stop_cond= 0;
while( 1 )
{
MPI_Irecv( &stop_cond_rank, 1, MPI_INT, left_rank, 123, MPI_COMM_WORLD, &stop_cond_request);
/* Compute Here and set stop condition accordingly */
if( stop_cond )
{
/* Cancel the left recv */
MPI_Cancel( &stop_cond_request );
if( rank != right_rank )
MPI_Send( &rank, 1, MPI_INT, right_rank, 123, MPI_COMM_WORLD );
break;
}
int did_recv = 0;
MPI_Test( &stop_cond_request, &did_recv, MPI_STATUS_IGNORE );
if( did_recv )
{
stop_cond = 1;
MPI_Wait( &stop_cond_request, MPI_STATUS_IGNORE );
if( right_rank != stop_cond_rank )
MPI_Send( &stop_cond_rank, 1, MPI_INT, right_rank, 123, MPI_COMM_WORLD );
break;
}
}
if( stop_cond )
{
/* Handle the stop condition */
}
else
{
/* Cleanup */
MPI_Cancel( &stop_cond_request );
}
这似乎是一个常见的问题,没有简单的答案。另外两个答案都存在可伸缩性问题。环形通信方法具有线性通信成本,而在单边的MPI_-Win
-解决方案中,单个进程将受到来自所有工作者的内存请求的冲击。这可能适用于较低数量的列组,但在增加列组计数时会带来问题
非阻塞集合可以提供更具可扩展性的更好解决方案。其主要思想是在所有级别上发布一个MPI\u Ibarrier
,除了在一个指定的根上。此根用户将通过MPI\u Irecv
侦听点对点停止消息,并在收到消息后完成MPI\u Ibarrier
棘手的部分是需要处理四种不同的情况{root,non-root}x{found,not found}。也可能发生多个列组发送停止消息,需要根上未知数量的匹配接收。这可以通过计算发送停止请求的列组数来解决
下面是一个在C中显示的示例:
#包括
#包括
#包括
最大常数=10000;
const int难度=20000;
int find_stuff()
{
int num_iters=rand()%iter_max;
对于(int i=0;i0;已找到计数--){
MPI_Recv(空、0、MPI_字符、MPI_任意源、停止标记、MPI_通信世界和状态);
printf(“来自%d\n的附加停止”,状态.MPI\u源);
}
返回1;
}
返回0;
}
int main()
{
MPI_Init(NULL,NULL);
整数秩;
MPI通信等级(MPI通信世界和等级);
srand(秩);
MPI请求根目录接收停止;
MPI请求所有接收停止;
if(秩==根){
MPI_Irecv(NULL、0、MPI_字符、MPI_任意源、停止标记、MPI_通信世界和根记录停止);
}否则{
//您可能需要在此处使用额外的通讯器,以避免与其他障碍物发生冲突
MPI Ibarrier(MPI通信世界和所有接收站);
}
而(1){
int found=find_stuff();
如果(找到){
printf(“排名%d发现了一些东西。\n”,排名);
//注意:我们不能将其发布为阻塞,否则reduce会出现死锁