【问题标题】:MPI non-blocking communication and pthreads difference?MPI非阻塞通信和pthreads的区别?
【发布时间】:2013-01-25 09:18:05
【问题描述】:

在 MPI 中,有像 MPI_IsendMPI_Irecv 这样的非阻塞调用。

如果我正在处理 p2p 项目,服务器会监听许多客户端。

一种方法:

for(int i = 1; i < highest_rank; i++){
    MPI_Irecv(....,i,....statuses[i]); //listening to all slaves
}
while(true){
   for( int i = 1; i < highest_rank; i++){
         checkStatus(statuses[i])
         if true do somthing
}

我可以做到的另一种旧方法是:

Server creating many POSIX threads, pass in a function, 
that function will call MPI_Recv and loop forever.

理论上,哪一个在服务器端执行得更快?如果有其他更好的方法来编写服务器,也请告诉我。

【问题讨论】:

    标签: client-server mpi p2p


    【解决方案1】:

    后一种解决方案对我来说似乎不是很有效,因为在 MPI 进程中管理 pthread 会产生所有开销。

    无论如何,我会将 MPI 代码重写为:

    for(int i = 1; i < highest_rank; i++){
       MPI_Irev(....,i,....requests[i]); //listening to all slaves
    }
    while(true){
       MPI_waitany(highest_rank, request[i], index, status);
       //do something useful
    
    }
    

    更好的是,您可以使用 MPI_Recv 和 MPI_ANY_SOURCE 作为消息源的等级。似乎您的服务器除了服务请求之外没有任何事情可做,因此无需使用异步接收。 代码是:

    while(true){
        MPI_Recv(... ,MPI_ANY_SOURCE, REQUEST_TAG,MPI_comm,status)
        //retrieve client id from status and do something
    }
    

    【讨论】:

    • 问:如果使用 MPI_ANY_SOURCE,我能知道是哪个药膏向我发送了这个请求吗?
    • @LouisTan 是的,检查这个基于该原则构建的主从模型lam-mpi.org/tutorials/one-step/ezstart.php
    • @pyCthon 很棒的教程,非常感谢!!
    【解决方案2】:

    在调用 MPI_Irecv 时,在调用 MPI_Test* 或 MPI_Wait* 并成功完成之前测试 recv 缓冲区是不安全的。直接测试缓冲区而不进行这些调用的行为取决于实现(范围从不太糟糕到段错误)。

    可以为每个远程等级设置一个具有一个 MPI_Irecv 的 1:1 映射。根据正在发送的数据量以及该数据一旦接收到的生命周期,这种方法可能会消耗不可接受的系统资源量。使用 MPI_Testany 或 MPI_Testall 可能会在消息处理和 CPU 负载之间提供最佳平衡。如果在等待传入消息时不需要进行非 MPI 处理,则 MPI_Waitany 或 MPI_Waital 可能更可取。

    如果有未完成的 MPI_Irecv 调用,但应用程序已达到正常处理的结尾,则 MPI_Cancel 那些未完成的调用是“必要的”。未能做到这一点可能会在 MPI_Finalize 中被捕获为错误。

    MPI_ANY_SOURCE 上的单个 MPI_Irecv(或只是 MPI_Recv,取决于消息处理的积极程度)也提供了一个合理的解决方案。如果接收到的数据量“大”并且可以在处理后安全丢弃,这种方法也很有用。一次处理单个传入缓冲区可以减少所需的总系统资源,但会以串行化处理为代价。

    【讨论】:

      【解决方案3】:

      让我来评论一下您使用 POSIX 线程(或可能存在的任何其他线程机制)的想法。同时从多个线程进行 MPI 调用需要使用 MPI_THREAD_MULTIPLE 的最高线程支持来初始化 MPI 实现:

      int provided;
      
      MPI_Init_thread(&argv, &argc, MPI_THREAD_MULTIPLE, &provided);
      if (provided != MPI_THREAD_MULTIPLE)
      {
          printf("Error: MPI does not provide full thread support!\n");
          MPI_Abort(MPI_COMM_WORLD, 1);
      }
      

      虽然支持来自不同线程的并发调用的选项在很久以前就已在 MPI 标准中引入,但仍有 MPI 实现难以提供完全工作的多线程支持。 MPI 完全是关于编写可移植的应用程序,至少在理论上是这样,但在这种情况下,现实生活与理论有很大不同。例如,在MPI_THREAD_MULTIPLE 级别初始化时,最广泛使用的开源 MPI 实现之一 - Open MPI - 仍然不支持本机 InfiniBand 通信(InfiniBand 是非常快速的低延迟结构,目前在大多数 HPC 集群中使用)并且因此切换到不同的,通常慢得多且延迟更高的传输,例如常规以太网上的 TCP/IP 或 InfiniBand 上的 IP。还有一些超级计算机供应商,他们的 MPI 实现根本不支持MPI_THREAD_MULTIPLE,这通常是因为硬件的工作方式。

      此外,MPI_Recv 是一个阻塞调用,它会在适当的线程取消(如有必要)方面造成问题。您必须确保所有线程以某种方式逃脱无限循环,例如通过让每个工作人员发送带有适当标签或其他协议的终止消息。

      【讨论】:

        猜你喜欢
        • 2014-04-04
        • 2020-08-30
        • 2011-08-28
        • 1970-01-01
        • 2022-01-02
        • 2015-08-17
        • 1970-01-01
        • 1970-01-01
        • 2012-08-24
        相关资源
        最近更新 更多