【问题标题】:Reading fortran direct access data and writing formatted data - faster with python than with fortran?读取 fortran 直接访问数据和写入格式化数据 - 使用 python 比使用 fortran 更快?
【发布时间】:2013-08-13 03:16:28
【问题描述】:

晚上好,

我有一个用 Fortran 编写的模拟,它会生成大量未格式化(直接访问)数据的文件。 从其中一些文件中,我想生成 ascii 人类可读的文件。

出于某种原因(在 python 中):

f = open(filename,'rb')
for i in xrange(0,N):
    pos = i * 64
    f.seek(pos)
    name = struct.unpack('ffff',f.read(16))
    print name[0],name[1],name[2],name[3]

只需要大约 4 秒(将输出通过管道传输到 shell 上的文件中),而这(在 Fortran 中)

 open (1,file=inputfile,access='direct',recl=64, action='read',status="OLD")
 open (2, file=outputfile, access="sequential", action="write",status="REPLACE")
 do i=1,(N)
     read(1, rec = i ) a,b,c,d
     write(2,*) a,b,c,d
 enddo

大约需要 20 秒。 我究竟做错了什么?在 Fortran 中有更快的方法吗?

最好的问候! 回复

【问题讨论】:

  • 尝试使用 fortran 程序写入标准输出并通过管道传输到输出文件。
  • thx - 好的,我试过了,但它并没有改变它需要的时间
  • 我认为,写入速度慢的原因是Fortran处理其输出单元的方式。 Here 是 IBM 的 XLF 正在做什么的描述(tl;dr:准备、锁定、写入、清理、解锁)。您可以尝试通过手动展开循环来合并多个读/写语句,或者简单地存储更大的数据块。在您的情况下,开销似乎是性能杀手。
  • 读入一个大数组,用一条语句写完整个东西
  • 我认为@Stefan 和乔治有道理。您可以预先分配一个大字符串,然后使用固定长度格式在其上打印,最后一次性输出整个字符串。当然,你可以一次做一个块(几千个数字)

标签: python file-io binary fortran ascii


【解决方案1】:

免责声明:我不知道,如果这能解决问题,但我知道,我可以得到高达 20 倍的时差。我也只测试了数据并没有读取它。


我正在研究 Fortran 与 python 的交互,因此想知道 Fortran 的二进制文件是如何构建的。在执行此操作时,我注意到 ifortgfortran 都可以选择打开或关闭缓冲 IO。

ifort:您可以在打开文件时指定关键字BUFFERED=['YES'|'NO']

gfortran:您可以将环境变量 GFORTRAN_UNBUFFERED_ALL 设置为 y|Y|1n|N|0,分别用于非缓冲和缓冲 IO。

请注意,gfortran 默认会缓冲 IO,而 ifort 不会。

我在底部的示例代码导致以下时间:

        |buffered|unbuffered
--------+--------+----------
ifort   |   1.9s |  18.2s
gfortran|   2.4s |  37.5s

此示例代码编写了一个直接访问二进制文件,其中包含 10M 数据集,每个数据集 12 字节。

PROGRAM btest
IMPLICIT NONE

INTEGER :: i

! IFORT
OPEN(11,FILE="test_d.bin",ACCESS="DIRECT",FORM="UNFORMATTED",RECL=3, &
& STATUS="REPLACE",BUFFERED="NO") ! ifort defines RECL as words
! GFORTRAN
!OPEN(11,FILE="test_d.bin",ACCESS="DIRECT",FORM="UNFORMATTED",RECL=12, &
!& STATUS="REPLACE") ! gfortran defines RECL as bytes

DO i = 1, 10000000
    WRITE(11,REC=i) i,i*1._8
END DO

CLOSE(11)

END PROGRAM

【讨论】:

  • 您可以只设置FORT_BUFFERED = true 或切换-assume buffered_io 为ifort。此外,您可以使用INQUIRE 语句确定RECL
【解决方案2】:

尝试使用 StreamIO 参见http://www.star.le.ac.uk/~cgp/streamIO.html 这应该允许在没有固定记录大小的情况下进行随机访问,并且可能会导致使用相同的底层操作系统。系统调用,从而有望获得相同的性能。

【讨论】:

  • 谢谢!我尝试了ACCESS="STREAM", FORM="FORMATTED" 并写了write(2,"(4(ES14.6E2,X))") a,b,c,d,但性能没有任何改善。即使我将打印的位数减少到 python 输出生成的位数以下,它也会慢得多。我还验证了读取数据非常快,因此打印需要相当多的时间。
  • 我怀疑阅读速度很慢,这是我希望您尝试 StreamIO 的地方。为了证实我的怀疑,注释掉 write 语句。只看不写。
  • 这正是我为验证哪个过程需要更多时间所做的。它在大约 3 秒内读取文件。为了确保我的编译器不会因为未使用读取的数据而跳过读取循环,我将最后的条目打印到命令行。
猜你喜欢
  • 2014-06-12
  • 1970-01-01
  • 2012-10-27
  • 2021-09-18
  • 2012-12-29
  • 2015-07-15
  • 2013-02-14
  • 2017-01-03
相关资源
最近更新 更多