1

我意识到这个问题之前已经被问,但不是在 IO 的上下文中。有没有理由相信:

!compiler can tell that it should write the whole array at once?
!but perhaps compiler allocates/frees temporary array?
write(UNIT) (/( arr(i), i=1,N )/)

会比以下更有效率:

!compiler does lots of IO here?
do i=1,N
   write(UNIT) arr(i)
enddo

对于打开为:

open(unit=UNIT,access='STREAM',file=fname,status='UNKNOWN')

有可能这将与编译器选项一起使用以关闭缓冲写入......

4

2 回答 2

3

正如@HighPerformanceMark 所建议的,这是我设置的一个简单基准:

使用 gfortran:

  program main
  implicit none
  include 'mpif.h'
  integer, parameter :: N = 1000000 
  integer :: unit = 22
  integer i
  real*8 arr(N)
  real*8 t1
  integer repeat
  external test1
  external test2
  external test3

  repeat=15

  call MPI_INIT(i)

  arr = 0
  call timeit(test1,repeat,arr,N,t1)
  print*,t1/repeat

  call timeit(test2,repeat,arr,N,t1)
  print*,t1/repeat

  call timeit(test3,repeat,arr,N,t1)
  print*,t1/repeat

  call MPI_Finalize(i)

  end

  subroutine timeit(sub,repeat,arr,size,time)
  include 'mpif.h'
  external sub
  integer repeat
  integer size
  real*8 time,t1
  real*8 arr(size)
  integer i
  time = 0
  do i=1,repeat
     open(unit=10,access='STREAM',file='test1',status='UNKNOWN')
     t1 = mpi_wtime()
     call sub(10,arr,size)
     time = time + (mpi_wtime()-t1)
     close(10)
  enddo

  return
  end

  subroutine test1(ou,a,N)
  integer N
  real*8 a(N)
  integer ou
  integer i
  do i=1,N
     write(ou),a(i)
  enddo
  return
  end

  subroutine test2(ou,a,N)
  integer N
  real*8 a(N)
  integer ou
  integer i
  write(ou),(a(i),i=1,N)
  return
  end

  subroutine test3(ou,a,N)
  integer N
  real*8 a(N)
  integer ou
  write(ou),a(1:N)
  return
  end

我的结果是(缓冲的):

temp $ GFORTRAN_UNBUFFERED_ALL=1 mpirun -np 1 ./test
   6.2392100652058922     
   3.3046503861745200     
   9.76902325948079409E-002

(无缓冲):

temp $ GFORTRAN_UNBUFFERED_ALL=0 mpirun -np 1 ./test
  2.7789104779561362     
  0.15584923426310221     
  9.82964992523193415E-002
于 2012-09-24T16:58:07.587 回答
1

我使用 gfortran (4.7.2 20120921) 和 ifort (13.0.0.079 Build 20120731) 编译并运行了上述基准代码。我的结果如下:

gfortran

          UNBUFFERED                BUFFERED
test1:    1.2614487171173097        0.20308602650960286     
test2:    1.0525423844655355        3.4633986155192059E-002
test3:    5.9630711873372398E-003   6.0543696085611975E-003

伊福特

          UNBUFFERED                BUFFERED
test1:    1.33864809672038          0.171342913309733
test2:    6.001885732014974E-003    6.095488866170247E-003
test3:    5.962880452473959E-003    6.007925669352213E-003

在这两种情况下,显式循环似乎test1是迄今为止最不利的(没有设置任何优化标志)。write(ou), (a(i), i=1, N)此外,使用英特尔编译器,无论您运行(案例 2)还是write(ou), a(1:N)(案例 3,与本案例中的简单 情况相同) ,执行时间都没有显着差异write(ou), a

顺便说一句,对于这个单线程进程,您也可以只使用 fortran 90(或 95?)内在子例程cpu_time,它对所有线程求和并以秒为单位返回时间。否则还有system_clock,它可以将经过的时钟周期数和时钟速率作为整数返回,可能精度更高。

于 2012-10-22T16:36:57.707 回答