在MPI中,有MPI_Isend
和MPI_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.
理论上,哪一个在服务器端执行得更快?如果有另一种更好的方法来编写服务器,请告诉我。
答案 0 :(得分:3)
后一种解决方案对我来说似乎并不高效,因为在MPI流程中管理pthreads会产生所有开销。
无论如何,我会把你的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
}
答案 1 :(得分:1)
调用MPI_Irecv时,在调用并成功完成AFTER MPI_Test *或MPI_Wait *之前测试recv缓冲区是不安全的。在不进行这些调用的情况下直接测试缓冲区的行为取决于实现(范围从非如此差到段错误)。
可以使每个远程等级的一个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,取决于消息处理需要多大程度)也提供了合理的解决方案。如果接收的数据量“大”并且可以在处理之后安全地丢弃,则该方法也是有用的。一次处理单个传入缓冲区可以减少所需的总系统资源,但代价是序列化处理。
答案 2 :(得分:0)
让我简单评论一下您使用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实现之一 - 开放式MPI - 在MPI_THREAD_MULTIPLE
初始化时仍然不支持本机InfiniBand通信(InfiniBand是非常快速的低延迟结构,现在在大多数HPC集群中使用)。因此,通过常规以太网或IP-over-InfiniBand,可以切换到不同的,通常更慢且具有更高延迟的传输,如TCP / IP。还有一些超级计算机供应商,其MPI实现根本不支持MPI_THREAD_MULTIPLE
,通常是因为硬件的工作方式。
此外,MPI_Recv
是一个阻塞调用,它会导致正确的线程取消问题(如果需要)。你必须确保所有线程以某种方式逃脱无限循环,例如通过让每个工作人员发送带有适当标签或其他协议的终止消息。