如何在FORTRAN中更快地写入二进制文件?



我有以下代码来写入二进制文件:

CALL system_clock(Time1, rate)
OPEN( 1, FILE='Test.bin', STATUS='UNKNOWN', ACCESS='STREAM')
DO 275 I=1,NDOF
  DO 274 J=1,UBW
    IF (S(I,J).NE.0) THEN
      WRITE (1) I
      WRITE (1) J+I-1
      WRITE (1) (S(I,J))
    ENDIF
  274 CONTINUE
275 CONTINUE
CLOSE(1)
CALL system_clock(Time2)
print *, "elapsed time: ", real(Time2-Time1) / real(rate)

我知道通过使用更少的WRITE语句我可以使它更快。因此,在循环中,我使用以下代码,它更快:

IF (S(I,J).NE.0) THEN 
WRITE (1) I, J+I-1,  (S(I,J)) 
ENDIF

有没有办法摆脱循环(因为它是耗时的)或做任何其他改变有一个更有效的代码?

请注意,在我的写作中,我希望有I,J +I-1和S(I,J)的顺序(只有非零值)。此外,由于我使用c++程序读取二进制文件,我必须使用流访问。

任何建议都非常感谢。

您可以做的一件事是颠倒处理数组的顺序。所以在你的do语句中,简单地把i换成j。这是因为数组S(i,j)是二维的,它在内存中的存储方式对访问速度非常重要。存储取决于所使用的编程语言标准,Fortran(与C相反,但与Matlab类似)以列为主形式使用数组存储。因此,访问内存的最有效方法是从第一行元素开始连续遍历数组的每一列。

我在生产代码中所做的是首先填充缓冲区,然后将其存储在一个写命令中。它比只写列或只写单个值要快得多。类似以下语句:

CALL system_clock(Time1, rate)
allocate the buffer with the sufficient size
offset = 0
buffer = 0
DO I=1,NDOF
  DO J=1,UBW
    IF (S(I,J) /= 0) THEN
      buffer(offset: offset + int_size-1) = transfer(I,buffer)
      offset = offset + int_size
      buffer(offset: offset + int_size-1) = transfer(J+I-1,buffer)
      offset = offset + int_size
      buffer(offset: offset + real_size-1) = transfer((S(I,J))
      offset = offset + real_size
    ENDIF
  end do
end do
OPEN( 1, FILE='Test.bin', STATUS='UNKNOWN', ACCESS='STREAM')
write (1) buffer(1:offset-1)
CLOSE(1)
CALL system_clock(Time2)
print *, "elapsed time: ", real(Time2-Time1) / real(rate)
实际上,遍历数组的顺序并没有那么重要。 I/O操作极大地降低了你的速度

注:请不要在Fortran 2003中以continue结束循环,这很伤人。

你还可以做一件事,我称之为手动循环展开。

CALL system_clock(Time1, rate)
OPEN( 1, FILE='Test.bin', STATUS='UNKNOWN', ACCESS='STREAM')
DO 275 I=1,NDOF
  DO 274 J=1,UBW,2
    IF (S(I,J).NE.0) THEN
      WRITE (1) I, J+I-1, S(I,J), I, J+I, S(I,J+1)
    ENDIF
  274 CONTINUE
275 CONTINUE
CLOSE(1)
CALL system_clock(Time2)
print *, "elapsed time: ", real(Time2-Time1) / real(rate)

可以考虑更改循环顺序的选项(在Fortran中,最左边的索引应该更改最快,因为矩阵的列主要存储),但我认为加速应该忽略不计,这是I/o所需要的时间。

EDIT:如果UBW是奇数,您应该确保J不会走得太远,以避免数组越界错误。

...
IF ((S(I,J) .NE. 0) .AND. (J .LT. UBW)) THEN
  WRITE (1) I, J+I-1, S(I,J), I, J+I, S(I,J+1)
ELSE
  WRITE (1) I, J+I-1, S(I,J)
ENDIF
...

相关内容

  • 没有找到相关文章

最新更新