Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/fortran/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Fortran 在MPI中,如何在使用多个可执行文件时获取通信器?_Fortran_Mpi_Distributed - Fatal编程技术网

Fortran 在MPI中,如何在使用多个可执行文件时获取通信器?

Fortran 在MPI中,如何在使用多个可执行文件时获取通信器?,fortran,mpi,distributed,Fortran,Mpi,Distributed,在MPI中,我们使用多个进程,这些进程不共享任何内容,只与recv/send操作通信。recv/send操作是针对通信器进行的,通信器可以是整个处理器组或其子集。基本命令包括: call MPI_Comm_size ( MPI_COMM_WORLD, nproc, ierr ) call MPI_Comm_rank ( MPI_COMM_WORLD, myrank, ierr ) 与所有处理器集关联的通讯器。MPI的一个有趣的特性是,我们可以使用以下命令同时运行多个可执行文件: mpirun

在MPI中,我们使用多个进程,这些进程不共享任何内容,只与recv/send操作通信。recv/send操作是针对通信器进行的,通信器可以是整个处理器组或其子集。基本命令包括:

call MPI_Comm_size ( MPI_COMM_WORLD, nproc, ierr )
call MPI_Comm_rank ( MPI_COMM_WORLD, myrank, ierr )
与所有处理器集关联的通讯器。MPI的一个有趣的特性是,我们可以使用以下命令同时运行多个可执行文件:

mpirun -n 3 prog1 : -n 2 prog2

其中3个节点分配给第一个可执行文件,2个节点分配给第二个可执行文件。然而,对于实际工作,人们希望有一个与prog1或prog2相关联的通信器。是否有一种不使用命令直接获取该信息的方法?MPI\u COMM\u SPLIT?

标准中没有规定此类预定义的通信器

伟大的哲学家贾格尔曾经说过“你不可能总是得到你想要的”,你在这里的最佳选择就是使用
MPI\u Comm\u split()
MPI\u Comm\u WORLD
MPI\u APPNUM
属性作为
color
参数

来自MPI 3.1标准第10.5.3章

10.5.3 MPI_APPNUM

MPI_COMM_WORLD有一个预定义的属性MPI_APPNUM。在Fortran中,属性是一个整数值。在C中, 该属性是指向整数值的指针。如果一个过程是 使用MPI_COMM_SPAWN_MULTIPLE生成,MPI_APPNUM是命令号 这就产生了当前的进程。编号从零开始。如果 进程是用MPI_COMM_SPAWN生成的,它将使MPI_APPNUM相等 归零。此外,如果进程不是由spawn调用启动的, 但是通过一种特定于实现的启动机制 多个过程规范,MPI_APPNUM应设置为数字 符合相应的工艺规范。特别是,如果是 开始于

mpiexec规范0[:规范1:规范2:…]

MPI_APPNUM应设置为相应规范的编号

如果应用程序不是使用MPI_COMM_SPAWN或 MPI_COMM_SPAWN_MULTIPLE和MPI_APPNUM在 特定于实现的启动机制的上下文,MPI_APPNUM是 未设置

MPI实现可以选择性地提供一种机制 通过info参数重写MPI_APPNUM的值。MPI 为所有生成调用保留以下键

appnum值包含 一个整数,用于覆盖 孩子

理由

当单个应用程序启动时,它能够 通过查看进程的大小来确定有多少个进程 MPI_通讯世界。由多个SPMD组成的应用程序 子应用程序无法确定有多少子应用程序 以及流程所属的子应用程序。虽然有 在特殊情况下,没有通用的机制来解决这个问题。 MPI_APPNUM提供了这样一种通用机制。(理由结束。)


另一种选择是使用MPI标准描述的客户机-服务器机制(可以找到关于这一点的章节)。这里的想法是编译两个独立的MPI应用程序。其中一个最终成为服务器并打开连接端口。另一个是必须连接到该端口的客户端。代码将如下所示:

mpirun -n <N1> server &
mpirun -n <N2> client
服务器:

program server

    use mpi_f08
    implicit none

    integer :: error
    type(MPI_Comm) :: intercomm

    real, dimension(5) :: data = [1,2,3,4,5]
    character(len=MPI_MAX_PORT_NAME) :: port_name

    ! Normal MPI initialization
    call MPI_Init(error)

    ! Here we open a port for incoming connections
    call MPI_Open_port(MPI_INFO_NULL, port_name, error)
    ! Copy it in order to pass the address to a client
    print*, "PORT NAME:", port_name
    ! Accept the incoming connection creating the intercommunicator
    call MPI_Comm_accept(port_name, MPI_INFO_NULL, 0, MPI_COMM_WORLD, intercomm, error)
    ! Send test data
    call MPI_Send(data, 5, MPI_FLOAT, 0, 0, intercomm)
    print*, "DATA SENT"
    ! Close connection
    call MPI_Comm_disconnect(intercomm, error)

    call MPI_Finalize(error)

end program server
客户:

program client
    use mpi_f08
    implicit none

    integer :: error
    type(MPI_Comm) :: intercomm
    type(MPI_Status) :: status

    real, dimension(5) :: data = [0,0,0,0,0]
    character(len=MPI_MAX_PORT_NAME) :: port_name

    call MPI_Init(error)

    ! Here we copy the port name obtained from the server
    print*, "Type in port name"
    read(*,*) port_name

    ! Establish a connection creating the intercommunicator
    call MPI_Comm_connect(port_name, MPI_INFO_NULL, 0, MPI_COMM_WORLD, intercomm, error)
    ! Receive test data
    call MPI_Recv(data, 5, MPI_FLOAT, 0, 0, intercomm, status, error)
    print*, "DATA RECEIVED", data
    ! Close connection
    call MPI_Comm_disconnect(intercomm, error)

    call MPI_Finalize(error)

end program client
在实际的程序中,您可能会发现其他一些将端口地址信息传输到客户端的方法(例如,名称发布或文件系统传输)。然后您可以像这样运行代码:

mpirun -n <N1> server &
mpirun -n <N2> client
mpirun-n服务器&
mpirun-n客户端

这种方法没有什么值得注意的。如果您只创建一个内部通讯器,那么每一方只会有一个MPI任务与合作伙伴代码进行通讯。如果您需要发送大量数据,您可能需要考虑创建多个互通器。此外,MPI标准这一部分的实现可能有点挑剔(例如,在OpenMPI 2.x中,有一个bug完全阻止了它的使用)。

对于任何有兴趣拆分MPI通信世界的人,我编写了一个小实用程序库(一个标题)。它将通讯器拆分为本地通讯器,并在它们之间建立内部通讯器。它解决了许多技术问题:

您可以在以下位置找到标题:

它还为同时运行多个程序和生成程序提供了相同的语法。如果您有任何问题或想法来扩展此功能,请在github上打开一个问题

例如,在您的第一个程序中,您执行以下操作:

MPMDHelper-MPMD;
MPI_Init(&argc,&argv);
MPMD.Init(MPI_COMM_WORLD,“programA”);

MPMD.local//问题是“不使用命令MPI\u COMM\u SPLIT”,因此这并不能真正回答海报的问题。他们为什么要避免使用非常有用的MPI_COMM_SPLIT例程是另一个问题…是的,我误解了这个问题。。。除非OP真的想问如何简单地将颜色传递给
MPI\u Comm\u split()
(在程序开始时并不昂贵)…这确实回答了我的问题。我必须使用MPI_COMM_SPLIT。我认为直接拥有这样一个通信器是有意义的,但事实并非如此。如果你想沿着这条路走,先启动服务器,然后
MPI\u Comm\u spawn()
客户端就不那么复杂了,您还可以避免副作用,例如在同一个内核上固定两个不同的MPI运行调用(因此是分时的),以MPI任务结尾。@GillesGouaillardet它是否仍然有可能过度订阅系统?此外,这可能需要添加更多的命令行选项(至少一个?)。使用客户机-服务器方法,还可以避免通过大量wa将不同应用程序的MPI任务放在同一个核心上