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会出现死锁