Bir simülasyondan Sıcaklık dağılımını temsil eden 512 ^ 3 dizisi elde ediyorum (Fortran'da yazılmıştır). Dizi, boyutu yaklaşık 1 / 2G olan bir ikili dosyada saklanır. Bu dizinin minimum, maksimum ve ortalamasını bilmem gerekiyor ve yine de Fortran kodunu yakında anlamam gerekeceği için, onu denemeye karar verdim ve aşağıdaki çok kolay rutini buldum.
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)
Bu, kullandığım makinedeki dosya başına yaklaşık 25 saniye sürüyor. Bu bana oldukça uzun geldi ve bu yüzden devam ettim ve Python'da şunları yaptım:
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)
Şimdi, bunun elbette daha hızlı olmasını bekliyordum, ama gerçekten şaşırmıştım. Aynı koşullar altında bir saniyeden az sürer. Ortalama, Fortran rutinimin bulduğundan sapıyor (ki ben de 128-bitlik kaymalarla çalıştırdım, bu yüzden ona bir şekilde daha çok güveniyorum), ancak sadece 7. önemli basamakta ya da öylesine.
Uyuşuk nasıl bu kadar hızlı olabilir? Demek istediğim, bu değerleri bulmak için bir dizinin her girişine bakmanız gerekiyor, değil mi? Fortran rutinimde çok daha uzun sürmesi için çok aptalca bir şey mi yapıyorum?
DÜZENLE:
Yorumlardaki soruları cevaplamak için:
- Evet, Fortran rutinini de 32-bit ve 64-bit kayanlarla çalıştırdım, ancak performans üzerinde hiçbir etkisi olmadı.
iso_fortran_env
128-bit float sağlayan kullandım .- 32-bit float kullanmak ortalamam biraz yanlış, bu yüzden hassasiyet gerçekten bir sorundur.
- Her iki rutini de farklı dosyalarda farklı sırayla çalıştırdım, bu yüzden önbelleğe alma, sanırım karşılaştırmada adil olmalıydı?
- Aslında MP'yi açmayı denedim, ancak aynı anda farklı konumlarda dosyadan okumayı denedim. Yorumlarınızı ve cevaplarınızı okuduktan sonra bu kulağa çok aptalca geliyor ve rutini çok daha uzun sürüyor. Dizi işlemlerini deneyebilirim ama belki bu gerekli bile olmayacak.
- Dosyalar aslında 1 / 2G boyutunda, bu bir yazım hatasıydı, Teşekkürler.
- Şimdi dizi uygulamasını deneyeceğim.
DÜZENLEME 2:
@Alexander Vogt ve @casey'nin cevaplarında önerdiklerini uyguladım ve bu kadar hızlı numpy
ama şimdi @Luaan'ın alabileceğimi belirttiği gibi bir hassaslık sorunum var. 32 bitlik bir kayan dizi kullanıldığında, hesaplanan ortalama sum
% 20 indirimdir. Yapıyor
...
real,allocatable :: tmp (:,:,:)
double precision,allocatable :: tmp2(:,:,:)
...
tmp2=tmp
mean=sum(tmp2)/size(tmp)
...
Sorunu çözer ancak hesaplama süresini artırır (çok fazla değil, fark edilir ölçüde). Bu sorunu aşmanın daha iyi bir yolu var mı? Dosyadaki single'ları doğrudan çiftlere okumanın bir yolunu bulamadım. Ve bundan nasıl numpy
kaçınılır?
Şimdiye kadarki tüm yardımlarınız için teşekkürler.