客户端-服务器-MPI无阻塞通信和pthreads的区别



在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.

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

后一种解决方案对我来说似乎不是很有效,因为在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一起用作消息源的级别。您的服务器似乎除了提供请求之外什么都不做,因此不需要使用异步recv。代码为:

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

调用MPI_Irecv时,在调用并成功完成AFTER MPI_test*或MPI_Wait*之前,测试recv缓冲区是不安全的。在不进行这些调用的情况下直接测试缓冲区的行为取决于实现(从不那么糟糕到segfault)。

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

如果存在未完成的MPI_Irecv调用,但应用程序已达到正常处理的末尾,则"有必要"MPI_Cancel这些未完成的调用。否则,MPI_Finalize中可能会出现错误。

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

让我评论一下您使用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实现之一open MPI在MPI_THREAD_MULTIPLE级别初始化时仍然不支持本机InfiniBand通信(InfiniBand是目前大多数HPC集群中使用的非常快速的低延迟结构),因此切换到不同的,通常慢得多并且具有更高延迟的传输,例如通过常规以太网的TCP/IP或通过InfiniBand的IP。还有一些超级计算机供应商,他们的MPI实现根本不支持MPI_THREAD_MULTIPLE,这通常是因为硬件的工作方式。

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

最新更新