在同一台机器上两个正在运行的 Fortran 程序之间传输数据(实数和整数数组)的最佳方法是什么?

发布于 2024-10-19 09:59:11 字数 44 浏览 8 评论 0原文

我们目前正在使用文件 I/O,但需要更好/更快的方法。示例代码将不胜感激。

We are currently using file I/O but need a better/faster way. Sample code would be appreciated.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

鹤舞 2024-10-26 09:59:11

通过使用文件进行传输,您已经实现了一种消息传递形式,因此我认为这对于此类程序来说是最自然的选择。现在,您可以自己编写一些东西,在可用时使用共享内存,在不可用时使用 TCP/IP 之类的东西 - 或者您可以使用已经这样做的库,例如 MPI,它广泛可用,有效,将利用共享内存如果您在同一台机器上运行,但也可以扩展到让您完全在不同的机器上运行它们,而无需更改代码。

因此,作为一个程序向第二个程序发送数据然后等待数据返回的简单示例,我们有两个程序,如下所示; first.f90

program first

    use protocol
    use mpi
    implicit none
    real, dimension(n,m) :: inputdata
    real, dimension(n,m) :: processeddata
    integer :: rank, comsize, ierr, otherrank
    integer :: rstatus(MPI_STATUS_SIZE)


    call MPI_INIT(ierr)
    call MPI_COMM_RANK(MPI_COMM_WORLD, rank, ierr)
    call MPI_COMM_SIZE(MPI_COMM_WORLD, comsize, ierr)

    if (comsize /= 2) then 
        print *,'Error: this assumes n=2!'
        call MPI_ABORT(1,MPI_COMM_WORLD,ierr)
    endif

    !! 2 PEs; the other is 1 if we're 0, or 0 if we're 1.
    otherrank = comsize - (rank+1)

    inputdata = 1.
    inputdata = exp(sin(inputdata))

    print *, rank, ': first: finished computing; now sending to second.'
    call MPI_SEND(inputdata, n*m, MPI_REAL, otherrank, firsttag, &
                  MPI_COMM_WORLD, ierr)
    print *, rank, ': first: Now waiting for return data...'
    call MPI_RECV(processeddata, n*m, MPI_REAL, otherrank, backtag, &
                  MPI_COMM_WORLD, rstatus, ierr)
    print *, rank, ': first: recieved data from partner.'

    call MPI_FINALIZE(ierr)

end program first

和 secondary.f90:

program second

    use protocol
    use mpi
    implicit none
    real, dimension(n,m) :: inputdata
    real, dimension(n,m) :: processeddata
    integer :: rank, comsize, ierr, otherrank
    integer :: rstatus(MPI_STATUS_SIZE)

    call MPI_INIT(ierr)
    call MPI_COMM_RANK(MPI_COMM_WORLD, rank, ierr)
    call MPI_COMM_SIZE(MPI_COMM_WORLD, comsize, ierr)

    if (comsize /= 2) then 
        print *,'Error: this assumes n=2!'
        call MPI_ABORT(1,MPI_COMM_WORLD,ierr)
    endif

    !! 2 PEs; the other is 1 if we're 0, or 0 if we're 1.
    otherrank = comsize - (rank+1)

    print *, rank, ': second: Waiting for initial data...'
    call MPI_RECV(inputdata, n*m, MPI_REAL, otherrank, firsttag, &
                  MPI_COMM_WORLD, rstatus, ierr)

    print *, rank, ': second: adding 1 and sending back.'
    processeddata = inputdata + 1 
    call MPI_SEND(processeddata, n*m, MPI_REAL, otherrank, backtag, &
                  MPI_COMM_WORLD, ierr)

    print *, rank, ': second: completed'

    call MPI_FINALIZE(ierr)

end program second

为了清楚起见,两个程序必须同意的东西可以在它们都使用的模块中,这里是 protocol.f90:(

module protocol
    !! shared information like tag ids, etc goes here

    integer, parameter :: firsttag = 1
    integer, parameter :: backtag  = 2

    !! size of problem
    integer, parameter :: n = 10, m = 20 
end module protocol 

用于构建可执行文件的 makefile 如下:)

all: first second

FFLAGS=-g -Wall
F90=mpif90

%.mod: %.f90
        $(F90) -c $(FFLAGS) $^    

%.o: %.f90
        $(F90) -c $(FFLAGS) $^    

first: protocol.mod first.o
        $(F90) -o $@ first.o protocol.o

second: protocol.mod second.o
        $(F90) -o $@ second.o protocol.o

clean:
        rm -rf *.o *.mod

和然后按如下方式运行这两个程序:

$ mpiexec -n 1 ./first : -n 1 ./second
           1 : second: Waiting for initial data...
           0 : first: finished computing; now sending to second.
           0 : first: Now waiting for return data...
           1 : second: adding 1 and sending back.
           1 : second: completed
           0 : first: recieved data from partner.
$

如果您向我们提供有关两个程序之间工作流程的更多信息,我们当然可以为您提供更相关的示例。

By using files for transfer, you're already implementing a form of message passing, and so I think that would be the most natural fit for this sort of program. Now, you could write something yourself that uses shared memory when available and something like TCP/IP when not - or you could just use a library that already does that, like MPI, which is widely available, works, will take advantage of shared memory if you are running on the same machine, but would then also extend to letting you run them on different machines entirely without you changing your code.

So as a simple example of one program sending data to a second and then waiting for data back, we'd have two programs as follows; first.f90

program first

    use protocol
    use mpi
    implicit none
    real, dimension(n,m) :: inputdata
    real, dimension(n,m) :: processeddata
    integer :: rank, comsize, ierr, otherrank
    integer :: rstatus(MPI_STATUS_SIZE)


    call MPI_INIT(ierr)
    call MPI_COMM_RANK(MPI_COMM_WORLD, rank, ierr)
    call MPI_COMM_SIZE(MPI_COMM_WORLD, comsize, ierr)

    if (comsize /= 2) then 
        print *,'Error: this assumes n=2!'
        call MPI_ABORT(1,MPI_COMM_WORLD,ierr)
    endif

    !! 2 PEs; the other is 1 if we're 0, or 0 if we're 1.
    otherrank = comsize - (rank+1)

    inputdata = 1.
    inputdata = exp(sin(inputdata))

    print *, rank, ': first: finished computing; now sending to second.'
    call MPI_SEND(inputdata, n*m, MPI_REAL, otherrank, firsttag, &
                  MPI_COMM_WORLD, ierr)
    print *, rank, ': first: Now waiting for return data...'
    call MPI_RECV(processeddata, n*m, MPI_REAL, otherrank, backtag, &
                  MPI_COMM_WORLD, rstatus, ierr)
    print *, rank, ': first: recieved data from partner.'

    call MPI_FINALIZE(ierr)

end program first

and second.f90:

program second

    use protocol
    use mpi
    implicit none
    real, dimension(n,m) :: inputdata
    real, dimension(n,m) :: processeddata
    integer :: rank, comsize, ierr, otherrank
    integer :: rstatus(MPI_STATUS_SIZE)

    call MPI_INIT(ierr)
    call MPI_COMM_RANK(MPI_COMM_WORLD, rank, ierr)
    call MPI_COMM_SIZE(MPI_COMM_WORLD, comsize, ierr)

    if (comsize /= 2) then 
        print *,'Error: this assumes n=2!'
        call MPI_ABORT(1,MPI_COMM_WORLD,ierr)
    endif

    !! 2 PEs; the other is 1 if we're 0, or 0 if we're 1.
    otherrank = comsize - (rank+1)

    print *, rank, ': second: Waiting for initial data...'
    call MPI_RECV(inputdata, n*m, MPI_REAL, otherrank, firsttag, &
                  MPI_COMM_WORLD, rstatus, ierr)

    print *, rank, ': second: adding 1 and sending back.'
    processeddata = inputdata + 1 
    call MPI_SEND(processeddata, n*m, MPI_REAL, otherrank, backtag, &
                  MPI_COMM_WORLD, ierr)

    print *, rank, ': second: completed'

    call MPI_FINALIZE(ierr)

end program second

For clarity, stuff that the two programs must agree on could be ina module they both use, here protocol.f90:

module protocol
    !! shared information like tag ids, etc goes here

    integer, parameter :: firsttag = 1
    integer, parameter :: backtag  = 2

    !! size of problem
    integer, parameter :: n = 10, m = 20 
end module protocol 

(A makefile for building the executables follows:)

all: first second

FFLAGS=-g -Wall
F90=mpif90

%.mod: %.f90
        $(F90) -c $(FFLAGS) $^    

%.o: %.f90
        $(F90) -c $(FFLAGS) $^    

first: protocol.mod first.o
        $(F90) -o $@ first.o protocol.o

second: protocol.mod second.o
        $(F90) -o $@ second.o protocol.o

clean:
        rm -rf *.o *.mod

and then you run the two programs as following:

$ mpiexec -n 1 ./first : -n 1 ./second
           1 : second: Waiting for initial data...
           0 : first: finished computing; now sending to second.
           0 : first: Now waiting for return data...
           1 : second: adding 1 and sending back.
           1 : second: completed
           0 : first: recieved data from partner.
$

We could certainly give you a more relevant example if you give us more information about the workflow between the two programs.

冷血 2024-10-26 09:59:11

您是否使用二进制(未格式化)文件 I/O?除非数据量很大,否则应该很快。

否则,您可以使用进程间通信,但会更复杂。您可能会找到 C 代码,您可以使用 ISO C 绑定从 Fortran 调用这些代码。

Are you using binary (unformatted) file I/O? Unless the data quantity is huge, that should be fast.

Otherwise you could use interprocess communication, but it would be more complicated. You might find code in C, which you could call from Fortran using the ISO C Binding.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文