Je reçois un 512^3 tableau représentant une distribution de la Température à partir d'une simulation (écrit en Fortran). Le tableau est stocké dans un fichier binaire, c'est environ 1/2G dans la taille. J'ai besoin de savoir le minimum, le maximum et la moyenne de ce tableau et que je vais bientôt besoin de comprendre le code Fortran de toute façon, j'ai décidé de lui donner un aller et venu avec la suite très facile de routine.
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)
Cela prend environ 25 secondes par fichier sur la machine que j'utilise. Ce qui m'a frappé comme étant plutôt long et donc je suis allé de l'avant et ne le suit en 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)
Maintenant, je m'attendais à cette à être plus rapide, bien sûr, mais j'ai été vraiment époustouflé. Il faut moins d'une seconde dans des conditions identiques. La moyenne s'écarte de celui de ma routine Fortran trouve (j'ai aussi couru 128 bits, les flotteurs, donc j'ai un peu de confiance plus), mais seulement à la 7ème chiffre significatif.
Comment peut-numpy être si rapide? Je veux dire, vous avez à regarder à chaque entrée d'une table pour trouver ces valeurs, droit? Suis-je en train de faire quelque chose de très stupide dans ma routine Fortran pour qu'il prenne beaucoup plus de temps?
EDIT:
Pour répondre aux questions dans les commentaires:
- Oui, aussi, j'ai couru la routine Fortran avec 32-bit et 64-bit flotte mais il n'a eu aucun impact sur les performances.
- J'ai utilisé
iso_fortran_env
qui fournit un cryptage 128 bits flotteurs. - En utilisant 32 bits flotteurs ma moyenne est éteint tout à fait un peu, donc la précision est vraiment un problème.
- J'ai couru les deux routines sur les différents fichiers dans un ordre différent, de sorte que la mise en cache doit avoir été juste dans la comparaison, je suppose ?
- J'ai effectivement essayé de l'ouvrir MP, mais à le lire à partir du fichier à différentes positions en même temps. Après avoir lu vos commentaires et de vos réponses cela semble vraiment stupide maintenant et il fait de la routine de prendre beaucoup plus de temps. Je pourrais faire un essai sur le tableau des opérations, mais peut-être de ne pas même être nécessaire.
- Les fichiers sont en fait 1/2G en taille, c'était une faute de frappe, Merci.
- Je vais essayer de la matrice de mise en œuvre maintenant.
EDIT 2:
J'ai mis ce que @Alexandre Vogt et @casey suggéré dans leurs réponses, et il est aussi rapide que numpy
, mais maintenant j'ai un problème de précision de @Luaan souligné que je pourrais obtenir. À l'aide d'une virgule flottante de 32 bits de la matrice de la moyenne calculée en sum
20% off. Faire
...
real,allocatable :: tmp (:,:,:)
double precision,allocatable :: tmp2(:,:,:)
...
tmp2=tmp
mean=sum(tmp2)/size(tmp)
...
Résout le problème, mais augmente le temps de calcul (ce n'est pas beaucoup, mais sensiblement).
Est-il une meilleure façon de contourner ce problème? Je ne pouvais pas trouver un moyen de lire les singles de directement le fichier en double.
Et comment est - numpy
éviter cela?
Merci pour toute l'aide jusqu'à présent.