我得到了一个512^3的数组,代表着一次模拟中的温度分布(用Fortran编写)。这个数组被存储在一个大约有1/2G大小的二进制文件中。我需要知道这个数组的最小值、最大值和平均值,因为我很快就需要理解Fortran代码,所以我决定尝试一下,并想出了以下非常简单的例程。
这在我使用的机器上每个文件大约需要 25 秒钟。我觉得这太长了,所以我用 Python 做了以下操作:
现在,我当然希望这会更快,但我真的很惊讶。在相同的条件下,它只需要不到一秒钟的时间。平均值与我的Fortran例程发现的值有所偏差(我还使用128位浮点数运行了它,所以我更加信任它),但只有第7个有效数字左右。
numpy怎么能这么快?我的意思是,你必须查看数组的每个条目才能找到这些值,对吗?我的Fortran例程需要花费如此长的时间,我是否做了一些非常愚蠢的事情?
编辑:
回答评论中的问题:
解决了问题,但会增加计算时间(不是很多,但还是可以明显感觉到)。 有没有更好的方法来解决这个问题?我找不到一种将单精度直接读取为双精度的方法。
integer gridsize,unit,j
real mini,maxi
double precision mean
gridsize=512
unit=40
open(unit=unit,file='T.out',status='old',access='stream',&
form='unformatted',action='read')
read(unit=unit) tmp
mini=tmp
maxi=tmp
mean=tmp
do j=2,gridsize**3
read(unit=unit) tmp
if(tmp>maxi)then
maxi=tmp
elseif(tmp<mini)then
mini=tmp
end if
mean=mean+tmp
end do
mean=mean/gridsize**3
close(unit=unit)
这在我使用的机器上每个文件大约需要 25 秒钟。我觉得这太长了,所以我用 Python 做了以下操作:
import numpy
mmap=numpy.memmap('T.out',dtype='float32',mode='r',offset=4,\
shape=(512,512,512),order='F')
mini=numpy.amin(mmap)
maxi=numpy.amax(mmap)
mean=numpy.mean(mmap)
现在,我当然希望这会更快,但我真的很惊讶。在相同的条件下,它只需要不到一秒钟的时间。平均值与我的Fortran例程发现的值有所偏差(我还使用128位浮点数运行了它,所以我更加信任它),但只有第7个有效数字左右。
numpy怎么能这么快?我的意思是,你必须查看数组的每个条目才能找到这些值,对吗?我的Fortran例程需要花费如此长的时间,我是否做了一些非常愚蠢的事情?
编辑:
回答评论中的问题:
- 是的,我也使用32位和64位浮点数运行了Fortran例程,但对性能没有影响。
- 我使用了
iso_fortran_env
,它提供了128位浮点数。 - 使用32位浮点数时,我的平均值相差很大,所以精度确实是一个问题。
- 我在不同的文件上以不同的顺序运行了两个例程,所以缓存应该在比较中是公平的,我猜?
- 我实际上尝试了open MP,但是要同时从文件的不同位置读取。根据您的评论和答案,现在听起来很愚蠢,并且这也使例程花费了更长的时间。也许我可以在数组操作上尝试一下,但可能甚至不需要。
- 这些文件实际上大小为1/2G,那是一个打字错误,谢谢。
- 我现在将尝试数组实现。
编辑2:
我实现了@Alexander Vogt和@casey在他们的回答中提出的方法,速度与numpy
一样快,但是如@Luaan所指出的那样,现在我遇到了精度问题。使用32位浮点数组,通过sum
计算的平均值偏离20%。执行以下操作:
...
real,allocatable :: tmp (:,:,:)
double precision,allocatable :: tmp2(:,:,:)
...
tmp2=tmp
mean=sum(tmp2)/size(tmp)
...
解决了问题,但会增加计算时间(不是很多,但还是可以明显感觉到)。 有没有更好的方法来解决这个问题?我找不到一种将单精度直接读取为双精度的方法。
numpy
是如何避免这个问题的?
非常感谢您迄今为止所提供的所有帮助。
minval()
、maxval()
和sum()
函数。此外,你在Fortran中混合了I/O操作和计算,但在Python中没有,这不是一个公平的比较;-) - Alexander Vogtmean=numpy.mean(mmap, dtype=np.float64)
。 - credondo