IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Python Discussion :

Problème "MemoryError" sur boucle


Sujet :

Python

  1. #1
    Membre Expert

    Homme Profil pro
    Inscrit en
    Janvier 2006
    Messages
    1 184
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Janvier 2006
    Messages : 1 184
    Par défaut Problème "MemoryError" sur boucle
    Bonjour,

    Par nécessité, je dois réécrire un vieux code VBA qui fonctionne très bien en Python.
    Il s'agit de récupérer des données SAP R3 et des les charger dans une DB.
    Les données sont récupérés par paquet de 200k lignes.
    On boucle ensuite sur ces lignes pour les insérer avec un "Insert into tbl select Va1 union all Select Val2 ...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    for iSAP in range(1,iLng_Lignes + 1):
    	iStrTemp = str(pSAP_Data(iSAP, "WA")).replace("'", "''")
    	iStrSQLValues = iStr_SQLValues + " select '" + iStr_Temp + "' union all "
    	iInt_NbLignesRAW = iInt_NbLignesRAW + 1
    	iInt_NbLignesTemp = iInt_NbLignesTemp + 1
    	if iInt_NbLignesRAW == 1000:
    		#=> insert
    		iInt_NbLignesRAW = 0
    		iStrSQLValues  =""
    pSAP_Data est l'objet renvoyé par SAP.
    Tout cela est fait dans une fonction à laquelle est passée pSAP_Data
    Le problème est que lors du "iStrSQLValues = iStr_SQLValues + " select '" + iStr_Temp + "' union all "", la mémoire occupée augmente et n'est jamais libérée et donc forcément, ça finit par planter.
    Quelqu'un aurait-il une idée pour résoudre le pb ?
    Merci.

  2. #2
    Expert confirmé Avatar de papajoker
    Homme Profil pro
    Développeur Web
    Inscrit en
    Septembre 2013
    Messages
    2 322
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Nièvre (Bourgogne)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Septembre 2013
    Messages : 2 322
    Par défaut
    bonjour
    Citation Envoyé par Kloun Voir le message
    Le problème est que lors du "iStrSQLValues = iStr_SQLValues + " select '" + iStr_Temp + "' union all "", la mémoire occupée augmente et n'est jamais libérée et donc forcément, ça finit par planter.
    utiliser + pour additionner des chaines est la pire méthode en python (dans une boucle!), préférer f-string (rapidité et mémoire)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    iStrSQLValues = f"{Str_SQLValues} select '{str(pSAP_Data(iSAP, 'WA')).replace(\"'\", \"''\")}' "
    python utilise un ramasse-miettes, il est impossible de libérer la mémoire d'une variable donnée (encore plus si déférencée)

    Par contre, tu peux appeler le garbage collector (rarement car ralenti le script) dans ce block ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    if iInt_NbLignesRAW == 1000:
    la doc : https://docs.python.org/fr/3/library/gc.html#gc.collect

  3. #3
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 715
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 715
    Par défaut
    Citation Envoyé par Kloun Voir le message
    Quelqu'un aurait-il une idée pour résoudre le pb ?
    Si vous êtes sûr que vous avez besoin de plus de mémoire... il faudrait comprendre pourquoi c'est le cas si vous avez une machine 64 bits car il est quand même plus probable qu'il y ait un problème dans le code (autre que celui que vous présentez).

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  4. #4
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 827
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 827
    Billets dans le blog
    1
    Par défaut
    Bonjour
    Citation Envoyé par Kloun Voir le message
    Le problème est que lors du "iStrSQLValues = iStr_SQLValues + " select '" + iStr_Temp + "' union all "", la mémoire occupée augmente et n'est jamais libérée et donc forcément, ça finit par planter.
    C'est pas ici que ça plante. A chaque itération l'ancienne chaine "iStrSQLValues" est d'abord libérée pour pouvoir stocker la nouvelle.

    Démo
    Code python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    #!/usr/bin/env python
    class myStr:
    	def __init__(self, chaine):
    		print("init [%s]" % repr(self))
    		self.chaine=chaine
     
    	def __del__(self):
    		print("del [%s]" % repr(self))
     
    	def __add__(self, other):
    		return self.__class__(self.chaine + other.chaine)
     
    	def __str__(self): return self.chaine
     
    a=myStr("x")
    b=myStr("y")
    for i in range(4):
    	tmp=a+b
    	print(id(tmp))

    Résultat
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    init [<__main__.myStr object at 0x7fec104e7160>]
    init [<__main__.myStr object at 0x7fec104e7df0>]
    init [<__main__.myStr object at 0x7fec104e7e50>]
    140651862589008
    init [<__main__.myStr object at 0x7fec104e7ee0>]
    del [<__main__.myStr object at 0x7fec104e7e50>]
    140651862589152
    init [<__main__.myStr object at 0x7fec104e7e50>]
    del [<__main__.myStr object at 0x7fec104e7ee0>]
    140651862589008
    init [<__main__.myStr object at 0x7fec104e7ee0>]
    del [<__main__.myStr object at 0x7fec104e7e50>]
    140651862589152
    del [<__main__.myStr object at 0x7fec104e7160>]
    del [<__main__.myStr object at 0x7fec104e7df0>]
    del [<__main__.myStr object at 0x7fec104e7ee0>]

    Les lignes en bleu montrent la création d'un nouveau tmp puis l'autre est alors détruit (lignes en rouge) durant la boucle. On peut aussi voir id(tmp) changer à chaque itération.
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  5. #5
    Expert confirmé Avatar de papajoker
    Homme Profil pro
    Développeur Web
    Inscrit en
    Septembre 2013
    Messages
    2 322
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Nièvre (Bourgogne)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Septembre 2013
    Messages : 2 322
    Par défaut
    Citation Envoyé par Sve@r Voir le message
    est d'abord libérée pour pouvoir stocker la nouvelle.
    ? del ne fait que déférencer la variable, aucunement libérer la mémoire. c'est au cg de libérer la mémoire des déférencés plus tard lors de sont passage.

  6. #6
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 715
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 715
    Par défaut
    c'est plus compliqué que çà: le référence count qui passe à 0 libère la mémoire mais le travail du GC en tache de fond c'est pour les boucles (les objets qui se référencent eux mêmes et pour lesquels le refcount ne passera pas à 0 lorsque "libérés").

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  7. #7
    Membre Expert

    Homme Profil pro
    Inscrit en
    Janvier 2006
    Messages
    1 184
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Janvier 2006
    Messages : 1 184
    Par défaut
    Merci pour les réponses.

    Python 32 bits parce que SAP, ça fonctionne pas en 64 bits.

    J'ai bien mis un gc.collect (j'en ai mis un peu partout)

    Le f-string, c'est peut-être un peu plus rapide. Du coup, ça plante plus rapidement.

    Citation Envoyé par Sve@r Voir le message
    Bonjour
    C'est pas ici que ça plante. A chaque itération l'ancienne chaine "iStrSQLValues" est d'abord libérée pour pouvoir stocker la nouvelle.
    Toutes les 1000 itérations, la mémoire utilisée augmente de 2M (et y'a que 8Go sur la machine).

  8. #8
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 827
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 827
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Kloun Voir le message
    Le f-string, c'est peut-être un peu plus rapide. Du coup, ça plante plus rapidement.
    Amusant (un peu d'humour ça peut pas faire de mal)

    Citation Envoyé par Kloun Voir le message
    Toutes les 1000 itérations, la mémoire utilisée augmente de 2M (et y'a que 8Go sur la machine).
    Bon déjà avec un Python 32 bits tu ne pourras gérer que 4G de RAM (32 bits quoi).
    Mais suis désolé, le souci ne peut pas provenir de la chaine

    Je viens de taper ce petit code...
    Code python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    #!/usr/bin/env python3
     
    iStr_SQLValues="Hello"
    iStr_Temp="World"
    for i in range(10000**2):
    	chaine=iStr_SQLValues + " select '" + iStr_Temp + "' union all " + str(i)
    	if (i % 1000000) == 0: print(i, chaine)

    Python a tout avalé sans broncher. Et j'ai examiné ma RAM pendant que ça tournait, bon ok elle a bougé durant le travail mais ses mouvements étaient des oscillations (évidemment mon ordi faisait d'autres choses) et jamais elle n'a monté en croissance infinie...

    Accessoirement je m'interroge sur pSAP_Data(iSAP, "WA") que tu appelles durant la boucle. Ne penses-tu pas qu'il faudrait t'intéresser à cette fonction? Peut-être la désactiver et retenter un test...? En tout cas c'est la seule inconnue de la boucle...
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  9. #9
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 715
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 715
    Par défaut
    Citation Envoyé par Kloun Voir le message
    Toutes les 1000 itérations, la mémoire utilisée augmente de 2M (et y'a que 8Go sur la machine).
    Si ça plante avec MemoryError, la mémoire alloué augmente certainement.... mais c'est pas ça qui va donner des pistes pour en trouver la cause et imaginer une solution.

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  10. #10
    Membre Expert

    Homme Profil pro
    Inscrit en
    Janvier 2006
    Messages
    1 184
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Janvier 2006
    Messages : 1 184
    Par défaut
    Citation Envoyé par Sve@r Voir le message
    Accessoirement je m'interroge sur pSAP_Data(iSAP, "WA") que tu appelles durant la boucle. Ne penses-tu pas qu'il faudrait t'intéresser à cette fonction? Peut-être la désactiver et retenter un test...? En tout cas c'est la seule inconnue de la boucle...
    Oui, ça vient de là (testé en remplaçant par une chaine bidon).
    Reste à savoir comment vider la mémoire du machin.
    En sortie de fonction, je fait un del et un gc.collect.
    Et dans la fonction appelante, je réinitialise tous les objets SAP.

  11. #11
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 827
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 827
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Kloun Voir le message
    Reste à savoir comment vider la mémoire du machin.
    Elle est de toi la fonction ?
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  12. #12
    Membre Expert

    Homme Profil pro
    Inscrit en
    Janvier 2006
    Messages
    1 184
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Janvier 2006
    Messages : 1 184
    Par défaut
    Houla non.
    Fourni par SAP. Mais faut se démerder pour s'en servir.
    win32com.client.Dispatch("SAP.Functions")
    Ca permet d'utiliser les RFC (Remote Function Call) SAP mais la doc est comment dire ... succincte (voire inexistante).

    Je vois bien une solution : lancer un process avec les param qui vont bien et attendre son retour (nb de lignes traitées ou -1 si KO).
    Mais ça dépasse mes faibles compétences.

  13. #13
    Expert confirmé Avatar de papajoker
    Homme Profil pro
    Développeur Web
    Inscrit en
    Septembre 2013
    Messages
    2 322
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Nièvre (Bourgogne)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Septembre 2013
    Messages : 2 322
    Par défaut
    En fait, avec python, j'ai connu qu'une fois un problème mémoire dans une grosse boucle:

    objets "étrangés" GLib que je recevais qui n'étaient jamais libérés de la mémoire
    l'appel au garbage m'avait sauvé car je n'avais aucun code python sur la lib (bibliothèque compilée, chargée par gi).

    note: une boucle passait, mais c'était une app graphique donc elle pouvait se reproduire 1 fois par minute suivant l'utilisateur (rafraichir une grille) et au bout d'une heure

  14. #14
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 715
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 715
    Par défaut
    Citation Envoyé par Kloun Voir le message
    Fourni par SAP. Mais faut se démerder pour s'en servir.
    win32com.client.Dispatch("SAP.Functions")
    Ca permet d'utiliser les RFC (Remote Function Call) SAP mais la doc est comment dire ... succincte (voire inexistante).
    Si c'est le client COM de SAP qui a des fuites mémoire (suite à des bugs ou a une utilisation inappropriée), il serait plus judicieux d'aller chercher de l'aide dans des forums SAP.


    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  15. #15
    Membre Expert

    Homme Profil pro
    Inscrit en
    Janvier 2006
    Messages
    1 184
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Janvier 2006
    Messages : 1 184
    Par défaut
    Je suis passé par le multithreading et le problème est contourné.
    Merci pour l'aide.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [MySQL] Problème sur Boucle While après un LEFT JOIN
    Par matperino dans le forum PHP & Base de données
    Réponses: 12
    Dernier message: 28/05/2007, 17h43
  2. [Quote] DVP quoté sur Bashfr
    Par Skyounet dans le forum La taverne du Club : Humour et divers
    Réponses: 16
    Dernier message: 26/09/2006, 18h52
  3. [VBA-E]Problème de triet effacement de doublon sur boucle
    Par baptbapt dans le forum Macros et VBA Excel
    Réponses: 2
    Dernier message: 04/09/2006, 11h06
  4. Quotes sur des valeurs numériques
    Par shadeoner dans le forum SQL Procédural
    Réponses: 2
    Dernier message: 05/05/2006, 14h56
  5. Problème quotes
    Par Anduriel dans le forum Langage
    Réponses: 6
    Dernier message: 16/11/2005, 19h04

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo