Я отримую масив 512 ^ 3, що представляє розподіл температури від моделювання (написаний у Фортрані). Масив зберігається у двійковому файлі розміром приблизно 1 / 2G. Мені потрібно знати мінімум, максимум і середнє значення цього масиву, і оскільки мені все одно скоро знадобиться зрозуміти код 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)
Зараз, я очікував, що це буде швидше, звичайно, але мене справді обдурило. Це займає менше секунди за однакових умов. Середнє значення відхиляється від знайденого моєю рутинною фортранською формою (яку я також використовував із 128-бітовими плаваючими знаками, тому я чомусь йому більше довіряю), але лише на 7-му значущому значенні чи близько того.
Як може Numpy бути таким швидким? Я маю на увазі, що вам потрібно переглянути кожен запис масиву, щоб знайти ці значення, чи не так? Я роблю щось дуже дурне у своїй рутині Фортрана, щоб це зайняло набагато більше часу?
РЕДАГУВАТИ:
Щоб відповісти на запитання в коментарях:
- Так, я також запускав процедуру Fortran із 32-бітними та 64-бітними плаваючими плавниками, але це не впливало на продуктивність.
- Я використовував,
iso_fortran_env
який забезпечує 128-бітові плаваючі дані. - Використання 32-розрядних плаваючих значень, однак, у мене трохи відключено, тому точність насправді є проблемою.
- Я запускав обидві підпрограми на різних файлах у різному порядку, тому кешування мало бути справедливим у порівнянні, я думаю?
- Я насправді намагався відкрити 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
уникнути?
Дякуємо за всю допомогу.