【发布时间】:2012-11-29 03:24:49
【问题描述】:
考虑以下几点:
subroutine send_to_friend(a,b,c,request)
implicit none
include 'mpif.h' !use mpi if you've built the mpif90 bindings...
real a,b,c
real buff(3)
integer tag,dest,ierr,request
tag = 50
dest = 0
buff(1) = a
buff(2) = b
buff(3) = c
call MPI_Isend(buff,3,MPI_REAL,dest,tag,MPI_COMM_WORLD,request,ierr)
return
end subroutine send_to_friend
这可能不起作用,因为buff 将被放入堆栈(无论如何,大多数现代编译器),但只要子例程退出,它就会被清除干净。分配数组也无济于事,因为根据here(第 10 节),当您退出过程时,分配的数组会自动解除分配——在 C 中,这将是内存泄漏(也很糟糕)。做这样的事情的正确方法是什么?我应该使用save 属性声明数组吗? (static 在 C 中)。这种设计一开始就存在缺陷吗?
【问题讨论】:
-
是的,我很想说设计本身就有问题。即使使用
save,如果您快速连续两次调用此子例程会发生什么?您可以将MPI_Bsend与“足够”的用户定义缓冲区空间一起使用,并管理缓冲区 MPI 的问题,但 Buffered Sends Are Evil -
@JonathanDursi -- 这就是您返回
request的原因 -- 以确保在您再次调用之前已发送数据。你应该怎么做这样的事情?当前进程在将数据发送到0时有很多事情要做......如果0太忙而无法立即接收消息,我不想等待......不是全部isend的目的是什么? -
如果您必须手动处理检查以前的请求以了解调用此子例程是否安全,那么我就是看不到此子例程的意义。如果您必须做一堆低级的事情才能安全地调用这个子例程,那么您并没有真正抽象出任何东西。也许你已经在你的代码中得到了更高层次的覆盖,但是仅仅看到这个例程就很难说出来。如果你真的想这样做,我只是建议使用 bsend(注意:不是 ibsend,出于同样的原因)或者传递一个缓冲区并让它安全地处理缓冲。
-
让我尝试更连贯地重写该评论;现在,即使使用
save,临时缓冲区的安全处理既是高层代码(调用前检查请求)和低层代码(将缓冲区填满数据)的责任)。这很尴尬且容易出错。我的建议是在调用代码中完成所有缓冲区处理(分配一个缓冲区,填充它,并将其传递给例程)或全部在较低级别的代码中(使用 Bsend 或您自己的缓冲区处理代码),只是不是两者。 -
@JonathanDursi -- 我的用例实际上比这更复杂。要发送(接收)的数据位于公共块中,这意味着我需要在调用过程中包含这些公共块——但这可能会引入命名空间冲突等。(注意,我无法控制那些设计决策)。我还希望能够从代码中的至少 2 个位置执行此操作,因此封装它似乎是个好主意。最后,
request都可以在本地处理(使用save)。第一次进入你不使用的功能MPI_Wait,每隔一次你都会这样做。