memory error - Python - Programmation
Marsh Posté le 21-11-2008 à 15:41:29
Je check ma boule de cristal et je te dis ça tout de suite
Mais en attendant, si on pouvait avoir des bouts de code pour savoir comment tu ouvres, fermes, et utilises tes fichiers ça pourrait sûrement aider au diagnostic
Regarder la consommation mémoire du processus python te serait également, j'en suis certain, bien utile
Marsh Posté le 21-11-2008 à 15:53:37
masklinn a écrit : Je check ma boule de cristal et je te dis ça tout de suite |
La boucle en question :
for fichier in ebm_files[:]:
MYDATA = EBM_file(fichier)
Voie = Record(MYDATA)
Voie.sauvegarde_fichier(repertoire+patient[indice_patient])
del(MYDATA)
del(Voie)
et la fonction de sauvegarde :
def sauvegarde_fichier(self,repertoire):
os.chdir(repertoire)
f = open(self.capteur+'.txt','wb')
for val in self.valeurs:
f.write("%3.3e\n" % (val))
f.close()
Marsh Posté le 21-11-2008 à 16:02:26
gaston__lagaffe a écrit : La boucle en question :
|
PS: Naming inconsistant avec du français et ne respecte pas la PEP8
Pour la sauvegarde, pourquoi utiliser os.chdir plutôt qu'on os.path.join pour créer un nom complet répertoire compris? Et tu utilises quelle version de Python?
Marsh Posté le 21-11-2008 à 16:28:28
masklinn a écrit :
|
Les fichiers EBM contiennent des données médicales acquises par différents capteurs : rythme cardiaque, activité cérébrale, saturation du sang en O2, etc ... La classe EBM_file parse le fichier EBM pour en extraire les informations enregistrées (qui ne sont pas celles acquises). La fonction __init__ ouvre et ferme le fichier EBM et stocke les champs. Il faut ensuite les traiter pour retrouver les valeurs enregistrées : c'est ce que je fais avec ma classe Record.
masklinn a écrit :
|
pas compris ... Je ne duplique pas la liste ebm_files, enfin je ne crois pas ...
masklinn a écrit :
|
Quelles sont les fonctions non standard que j'utilise (mises à part les objets EBM_file et Record spécifiques au format EBM pour lesquelles à mon avis il n'existe aucune classe pré-écrite) ? Quelles fonctions standard devrais-je utiliser ?
masklinn a écrit :
|
C'est bien ce que j'avais cru comprendre, mais bon je ne savais pas quoi tenter face à ce memory error, alors bon ...
masklinn a écrit : |
C'est quoi la PEP8 ?
masklinn a écrit : |
parce que je me suis pris la tête avec os.path.join et que ça génère des erreurs à cause de l'encodage des alors qu'avec un os.chdir ça marche. J'ai pas d'autre explication ^^
Marsh Posté le 21-11-2008 à 16:33:47
gaston__lagaffe a écrit :
|
ok.
gaston__lagaffe a écrit : pas compris ... Je ne duplique pas la liste ebm_files, enfin je ne crois pas ... |
Si, ebm_files[:] ça slice toute la liste => ça en crée une copie
gaston__lagaffe a écrit : Quelles sont les fonctions non standard que j'utilise (mises à part les objets EBM_file et Record spécifiques au format EBM pour lesquelles à mon avis il n'existe aucune classe pré-écrite) ? Quelles fonctions standard devrais-je utiliser ? |
C'était juste ça
gaston__lagaffe a écrit : C'est bien ce que j'avais cru comprendre, mais bon je ne savais pas quoi tenter face à ce memory error, alors bon ... |
Ben t'as apparement un memleak donc faut voir ce qui leak et où.
gaston__lagaffe a écrit : C'est quoi la PEP8 ? |
Python Style Guide.
gaston__lagaffe a écrit : parce que je me suis pris la tête avec os.path.join et que ça génère des erreurs à cause de l'encodage des alors qu'avec un os.chdir ça marche. J'ai pas d'autre explication ^^ |
mouais
essaie de t'inspirer de trucs genre http://mail.python.org/pipermail/p [...] 93782.html, http://utcc.utoronto.ca/~cks/space [...] emoryLeaks ou http://mg.pov.lt/blog/hunting-python-memleaks pour tenter de trouver où tu leak de la mémoire.
Marsh Posté le 29-11-2008 à 18:41:48
Y a des chances que le problème soit dans ta classe Record, non ?
Marsh Posté le 29-11-2008 à 21:25:54
e_esprit a écrit : Y a des chances que le problème soit dans ta classe Record, non ? |
c'est possible ... mais pas forcément ! Ca plante de façon aléatoire après plusieurs itérations à un endroit différent à chaque fois. La classe Embla est assez simple, on lit plusieurs octets, on calcule un ID et une valeur et en fonction de l'ID calculé, on associe la valeur calculée à tel ou tel attribut (façon switch)
par contre, la classe record est plus complexe : on effectue une succession d'opérations sur les valeurs enregistrées pour retrouver les valeurs mesuréees.
En tout cas, quand je fais tourner en 2 fois le programmes (les 7 premiers fichiers puis les 8 derniers), ça tourne sans planter et ça fonctionne bien...
Marsh Posté le 29-11-2008 à 21:30:00
T'as redéfini les méthodes __del__ sur tes objets ?
Si oui peut-être de façon incomplète ?
Marsh Posté le 29-11-2008 à 22:00:38
e_esprit a écrit : T'as redéfini les méthodes __del__ sur tes objets ? |
euh non, pas redéfini ... Naïvement j'imaginais que ça supprimait toute l'instance, mais c'est peut être pas le cas ... Vais essayer ça ! Merci !
Marsh Posté le 30-11-2008 à 00:23:58
e_esprit a écrit : T'as redéfini les méthodes __del__ sur tes objets ? |
quel intérêt de faire des del, surtout pour un débutant ???
Marsh Posté le 30-11-2008 à 00:54:52
Taz a écrit : |
quelle autre solution proposes-tu pour mon problème ?
Marsh Posté le 30-11-2008 à 01:49:47
gaston__lagaffe a écrit : quelle autre solution proposes-tu pour mon problème ? |
montrer ton code ou aller voir une cartomancienne.
surtout que bon, même dans des applis en python de plusieurs millions de sloc, tu ne te sers grosso-merdo de del que pour effacer des clefs dans un dict.
T'as genre une boucle infinie qui claque d'abord sur de la mémoire qu'autre chose. 'tain, si tu commencez par donner et regarder ta stacktrace, tu saurais immédiatement d'où ça vient ...
(et biensur la gestion de la mémoire est automatique en python, c'est pas la peine de faire des del pour le plaisir)
Marsh Posté le 30-11-2008 à 02:29:06
Taz a écrit : |
J'ai un problème pour montrer mon code : ça s'inscrit dans un projet de recherche scientifique et je suis tenu par le secret professionnel pour préserver la propriété intellectuelle. J'ai tout à fait conscience que ça rend beaucoup plus difficile de me répondre, mais bon, je fais quoi ?
Concernant la stacktrace, j'ai juste un MemoryError qui tombe de façon aléatoire après quelques itérations. J'ai essayé de changer l'ordre des fichiers, ça ne change rien; ça plante toujours, jamais au même endroit, jamais pendant le même fichier. Un coup lorsque j'ajoute un entier ou un float à une liste, un coup lorsque j'applique un masque binaire sur un autre vecteur binaire, etc ... A priori rien de super lourd en mémoire. Je l'ai essayé sur des pcs différents, ça plante à chaque fois, y compris sur des pcs haute performance.
Comme la gestion de la mémoire sous python a l'air un peu bizarre et que j'y connais pas grand chose, j'ai essayé de poser la question pour voir si qqn aurait une idée. Si personne n'a d'idée, c'est pas grave je m'arrangerai pour le faire en 2 fois. Ou alors je passerai sur un autre langage. C'est clair que la quantité de données à traiter est assez lourde; le résultat que je cherche prend tout de même 1,15Go (en moyenne) ...
Marsh Posté le 30-11-2008 à 10:30:00
Elle est pas bizarre du tout la gestion de la mémoire.
C'est navrant ton attitude de fuite en avant et ton refus de nous montrer ton code: tu crois vraiment que ton code de débutant intéresse les chinois du FBI ? Changer de langage pour un autre que tu ne connais pas non plus ne changera rien si ton code et ton algo sont mauvais. Si t'as 2G de données et que tu t'amuses à les charger 2x, bah ton windows 32bits il va pas aimer.
Marsh Posté le 30-11-2008 à 13:26:31
Taz a écrit : Elle est pas bizarre du tout la gestion de la mémoire. |
je crois que tu n'as pas bien compris : je suis tenu par le secret professionnel. Ca n'a rien à voir avec les chinois ou le FBI, mais avec le respect de la propriété intellectuelle dans le cadre de la recherche scientifique médicale. Crois tu vraiment que les ingénieurs de microsoft ont le droit de venir déposer leur code sur des forums ? Personnellement, je surfe en permanence entre le secret médical et la propriété intellectuelle; j'ai pas trop le choix en bossant dans la recherche médicale ... Et je ne parle même pas ici du format propriétaire des fichiers que je cherche à parser ... Le parser qu'ils vendent coute 1000 euros; j'imagine même pas la tête qu'ils feront si je mets un code en ligne totalement libre d'accès.
En l'occurrence, j'ai aussi une formation d'ingénieur en informatique donc pas débutant complet dans la programmation. J'ai pas mal travaillé en traitement du signal sous matlab et surtout scilab, donc le même parser existe sous scilab et tourne sans problème, mais en 2 heures ... Nous aurions besoin de maintenant travailler avec de l'objet, et j'ai eu envie de m'intéresser à python, voilà tout!
Et je continue de penser que la gestion de la mémoire est bizarre : il gère la mémoire tout seul, résultat quand je dois parser 15 fichiers d'affilée en utilisant une boucle for, il plante, alors que si je le fais à la main, il ne plante pas; ça a l'air assez mal foutu quand même.
Concernant les données que j'ai à traiter, je le répète, j'ai au départ 15 fichiers qui occupent au total environ 150 Mo, il s'agit de les parser en effectuant quelques traitements dessus. Ces traitements se font en 2 étapes. La première étape consiste juste à de la lecture d'octets utilisés pour le calcul d'un ID et d'une valeur, ensuite, à la manière d'un switch on affecte la valeur à tel ou tel attribut en fonction de la valeur de l'ID. Dans la deuxième étape, on réutilise l'ensemble des champs remplis dans la première étape (des masques, des gains, des fonctions de calibration, des booléens, des vecteurs, etc ...) de manière à calculer les valeurs physiologiques enregistrées lors de l'examen médical. En l'occurrence, ça plante aléatoirement dans des fichiers différents, aussi bien dans la première que dans la deuxième étape, à n'importe quelle ligne de code. Au final, je sauvegarde les data dans des fichiers txt par coté pratique et ces 15 fichiers txt prennent 1,15Go de mémoire. Si je retire cette étape de sauvegarde, ça plante quand même. Ce n'est donc pas elle qui fait planter.
Le problème ne peut pas venir des données à charger car quand je le fais fichier par fichier à la main, ça marche sans problème, la machine est donc tout à fait capable de le faire. Par contre, c'est bien au niveau des itérations que ça plante. il y a forcément des choses qu'il n'efface pas des itérations précédentes et qui occupent de la mémoire pour rien, mais je n'arrive pas à comprendre quoi !
Marsh Posté le 30-11-2008 à 13:30:22
gaston__lagaffe a écrit : il y a forcément des choses qu'il n'efface pas des itérations précédentes et qui occupent de la mémoire pour rien, mais je n'arrive pas à comprendre quoi ! |
Et je t'ai fourni des liens sur la recherche de memory leaks en python...
Python a une gestion de la mémoire très simple par refcount, si tu as un memleak c'est 90% du temps parce que tu conserves des références sur des données dont tu n'as plus besoin, c'est donc un problème dans ton implémentation.
Il n'y a toujours pas de magiciens dans le coin, donc on peut pas t'aider plus que ça.
Marsh Posté le 30-11-2008 à 13:32:17
Dans ce cas, tu peux forcer l'appel au GC en utilisant del.
Marsh Posté le 30-11-2008 à 13:34:46
KangOl a écrit : Dans ce cas, tu peux forcer l'appel au GC en utilisant del. |
Cf le code au dessus, il en a déjà mis, mais si tu sais pas où est le leak tu vas pas appeler del (ou faire un = None) sur les bons éléments, et le problème ne change pas
C'est pas possible de résoudre des problèmes de perfs sans profiler pour savoir d'où viennent ces problèmes, et un memleak c'est un problème de perfs.
Marsh Posté le 30-11-2008 à 14:16:37
masklinn a écrit : |
Oui mais justement, pour le moment je n'ai pas encore réussi à voir ce qui n'allait pas. Le nombre de références n'augmente pas. J'ai pas encore tout testé c'est vrai.
Si personne n'a d'idée, c'est pas grave, je voulais poser la question, je me doute que c'est pas facile d'y répondre, si c'est impossible, tant pis
Marsh Posté le 30-11-2008 à 15:38:22
Taz a écrit : |
Je lui ai pas conseillé de le faire, je lui ai demandé si il l'avait fait, ce qui aurait pu être la cause de son problème.
Marsh Posté le 30-11-2008 à 15:42:11
gaston__lagaffe a écrit : |
Mais c'est pas du tout impossible
Je suis sur que Python propose des lib qui te permettent de profiler ton application, pour voir où passe la mémoire..
Marsh Posté le 30-11-2008 à 16:01:18
esox_ch a écrit : |
oui c'est un peu ce que je cherche. L'idéal serait de pouvoir faire un état de la mémoire. Dans l'absolu c'est pas gravissime, le programme marche, il faut juste le faire tourner 2 fois ...
Marsh Posté le 30-11-2008 à 16:33:50
bon touchage de nouilles sur tes 30 lignes de python appartenant à la NASA.
Marsh Posté le 30-11-2008 à 19:08:30
gaston__lagaffe a écrit : |
Alors tape "profiler python" dans google et tu vas trouver ce que tu cherches.
Marsh Posté le 30-11-2008 à 19:43:49
esox_ch a écrit : |
Ca va le mener à cProfiler et hotshot qui sont des CPU/call profilers, j'ai donné 2 ou 3 liens indiquant la procédure de base et surtout le module à utiliser (gc) sauf à la limite si il est sous Solaris, je ne sais pas ce que le python instrumenté donne, DTrace fournit potentiellement plus d'infos.
Marsh Posté le 30-11-2008 à 19:50:25
Bon je n'ai pas non plus dit que c'était le premier lien..
Et bien là je crois qu'il a vraiment tout ce qu'il lui faut pour résoudre son problème.. Maintenant s'il préfère livrer un programme qu'il faut faire marcher 2 fois ...
Marsh Posté le 30-11-2008 à 21:59:43
esox_ch a écrit : Bon je n'ai pas non plus dit que c'était le premier lien.. |
Je n'ai rien à livrer, c'est un projet de recherche, je n'ai donc pas de cahier des charges et à l'heure actuelle, il n'y a rien comme concurrence. Je travaille dans un contexte où toute amélioration est la bienvenue. Et puis, j'ai fait un parser sous scilab qui permet de tout parser en une seule fois, il est juste très long...
Je regarderai ça quand je pourrai, merci à tout le monde pour les conseils.
Marsh Posté le 21-11-2008 à 15:37:00
Bonjour,
je dois parser une quinzaine de fichiers (dans un format propriétaire) avec python. ça représente au total 150Mo de données à parser. J'ai écrit le parser qui marche très bien et je parse les fichiers un à un dans une boucle, sauf que ... systématiquement ça plante lors de la septième itération avec un "memory error". A la fin de chaque itération, une fois le fichier parsé, les données sont retranscrites dans un fichier texte et le fichier fermé. Quand je relance sur les fichiers restant, ça tourne sans problème.
Quelqu'un aurait-il une idée de la raison de cette erreur de mémoire ? C'est assez pénible de devoir faire tourner le programme en 2 fois ...
Je ne manie python que depuis une petite dizaine de jours, help me !