2017-02-20 58 views
3

我正在开发具有编译语言(Fortran 95)的代码,该编译语言对大型星系目录进行了某些计算。每次执行一些更改时,我都会编译并运行代码,只需要用磁盘上的星系数据读取ASCII文件大约需要3分钟。这是浪费时间。诀窍在成本汇编之间更快地从硬盘中读取数据

如果我在IDL或Matlab中开始这个项目,那么它会有所不同,因为包含数组数据的变量将保存在不同编译之间的内存中。

但是,我认为可以做一些事情来加速来自磁盘的令人不安的读取,例如将文件放在假的RAM分区或其他东西中。

+0

为了更好地匹配我选择的答案,我稍微更改了标题。这个答案并不适合我原来的答案100%(没有关于如何在RAM中做分区的线索),但它不太有用,不会奖励它的绿色标签。我将特意发布有关RAM目录的另一个问题。 – Mephisto

+1

您是否做了一些实际测量,或者您是否猜测瓶颈是磁盘I/O而不是解析ASCII数据格式?假设你有足够的RAM用于虚拟硬盘,你可能还有足够的磁盘缓存可用,所以很可能你已经大部分都是从内存中读取数据。接受的答案暗示了这一点。 –

+0

@DanMašek我忽略了你提出的具体内容,但是我认为登录后第一次执行代码的时间要比连续读取的时间长。另外,当文件正在读取时,TOP命令不会显示100%的cpu活动,所以可能是硬盘读取问题。 – Mephisto

回答

6

而不是在RAM磁盘上的细节我建议你从ASCII数据库切换到二进制。这里是一个非常简单的例子...随机数的数组,存储为ASCII(ASCII.txt)和二进制日期(binary.bin):

program writeArr 
    use,intrinsic :: ISO_Fortran_env, only: REAL64 
    implicit none 
    real(REAL64),allocatable :: tmp(:,:) 
    integer :: uFile, i 

    allocate(tmp(10000,10000)) 

    ! Formatted read 
    open(unit=uFile, file='ASCII.txt',form='formatted', & 
     status='replace',action='write') 
    do i=1,size(tmp,1) 
    write(uFile,*) tmp(:,i) 
    enddo !i 
    close(uFile) 

    ! Unformatted read 
    open(unit=uFile, file='binary.bin',form='unformatted', & 
     status='replace',action='write') 
    write(uFile) tmp 
    close(uFile) 

end program 

下面是结果在大小方面:

:> ls -lah ASCII.txt binary.bin 
-rw-rw-r--. 1 elias elias 2.5G Feb 20 20:59 ASCII.txt 
-rw-rw-r--. 1 elias elias 763M Feb 20 20:59 binary.bin 

因此,您在存储方面节省了约3.35倍。 现在到了有趣的部分:在...

program readArr 
    use,intrinsic :: ISO_Fortran_env, only: REAL64 
    implicit none 
    real(REAL64),allocatable :: tmp(:,:) 
    integer :: uFile, i 
    integer :: count_rate, iTime1, iTime2 

    allocate(tmp(10000,10000)) 

    ! Get the count rate 
    call system_clock(count_rate=count_rate) 

    ! Formatted write 
    open(unit=uFile, file='ASCII.txt',form='formatted', & 
     status='old',action='read') 

    call system_clock(iTime1) 
    do i=1,size(tmp,1) 
    read(uFile,*) tmp(:,i) 
    enddo !i 
    call system_clock(iTime2) 
    close(uFile) 
    print *,'ASCII read ',real(iTime2-iTime1,REAL64)/real(count_rate,REAL64) 

    ! Unformatted write 
    open(unit=uFile, file='binary.bin',form='unformatted', & 
     status='old',action='read') 
    call system_clock(iTime1) 
    read(uFile) tmp 
    call system_clock(iTime2) 
    close(uFile) 
    print *,'Binary read ',real(iTime2-iTime1,REAL64)/real(count_rate,REAL64) 

end program 

回读的结果是

ASCII read 37.250999999999998  
Binary read 1.5460000000000000 

所以,> 24的一个因素!

因此,不要考虑其他任何事情,请先切换到二进制文件格式。

+0

当然,还有很多二进制格式更适合复杂的数据,并且比简单的Fortran二进制文件更具可移植性。其中我建议你考虑HDF5。 –

+0

这是一个非常棒的答案,对很多人来说都很有用(+1),但是原始文件有多种类型(第1列是字符,第2列是整数,其他列是浮点...),我定义了派生类型。编写二进制文件时,我不确定如何处理这个问题。我还有其他的代码,我去了二进制文件,可以在合理的时间内存储和读取16000x16000双精度数组。 – Mephisto

+1

但是,您将ASCII文件读取为派生类型可能适用于未格式化的文件。例如,读取整数分量,然后读取真实分量,等等。如果遇到问题,请提出其他问题。 – Ross