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 :

désimporter un module, import local, liberation mémoire


Sujet :

Python

  1. #1
    Membre éprouvé
    Homme Profil pro
    Vagabong étudiant en annalyse du signal.
    Inscrit en
    Avril 2019
    Messages
    127
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 26
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Vagabong étudiant en annalyse du signal.
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Avril 2019
    Messages : 127
    Par défaut désimporter un module, import local, liberation mémoire
    Bonjour,

    Je cherche un moyen d'importer un module juste quand j'en ai besoin puis de le désimporter dès que je m'en suis servi.
    Par exemple, numpy prend 365 Mo en RAM dès qu'on l'importe. J'aimerai bien pouvoir libérer cette mémoire dès que j'ai fini de m'en servir.

    J'ai essayé 'del', mais ça fait rien, j'ai donc essayé de forcer le ramasse-miette à faire le ménage mais il nettoie pas les modules...
    J'ai essayé '__import__' dans une fonction mais quand on sort de la fonction, le module reste importé.
    J'ai regardé du coté 'importlib' mais j'ai pas réussi non plus...

    Un exemple de ce que j'aimerai réussir à faire:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    >>> def foo(arg):
    ...     """Fonction qui utilise potentielement un module lourd."""
    ...     if arg:
    ...         module = __import__("numpy")
    ...         ... # Utilisation du module
    ...         # Suppression du module, libération de la mémoire (A)
    >>> foo(1) # (B)
    >>> # A cet endroit, je veux que la mémoire soit libérée, que se soit en (A) ou par le ramasse-miette en (B).
    Est-ce que vous avez des pistes?

  2. #2
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 679
    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 679
    Par défaut
    Salut,

    A priori un module est un objet comme un autre, tant qu'il a des référence, il ne pourra pas être "détruit" au sens "garbage collector"... Ce qui veut dire que la mémoire alloué ne sera pas rendue mais utilisable pour d'autres objets.

    Ceci dit, sur un environnement système à mémoire virtuelle, la taille de la mémoire virtuelle et la mémoire vive (la RAM) ne sont pas gérées de la même façon: la RAM alloué à un processus correspond aux pages physiques nécessaires à l'exécution du code.
    Lorsqu'elles ne sont plus utilisées depuis un certain temps et que le système a besoin de RAM, il va la réclamer aux différents processus (en sauvegardant leur état si nécessaire sur ce qu'on appelle des fichiers de pagination).

    Et lorsqu'il n'y a plus assez de mémoire physique, le système passe son temps à réclamer la mémoire, les disques tournent (s'ils sont mécaniques) , çà chauffe et çà rame. Ajouter de la mémoire, lancer moins de processus, avoir des disques plus rapides,... sont les seules solutions.

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

  3. #3
    Expert confirmé
    Avatar de jurassic pork
    Homme Profil pro
    Bidouilleur
    Inscrit en
    Décembre 2008
    Messages
    4 181
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Bidouilleur
    Secteur : Industrie

    Informations forums :
    Inscription : Décembre 2008
    Messages : 4 181
    Par défaut
    hello,
    Citation Envoyé par robinechuca Voir le message
    Par exemple, numpy prend 365 Mo en RAM dès qu'on l'importe. J'aimerai bien pouvoir libérer cette mémoire dès que j'ai fini de m'en servir.
    cela m'étonne un peu car chez moi le module numpy prends 11.418 Mo (windows 10 python 3.9). Quel O.S et quelle version de python utilises-tu ? Comment effectues-tu tes mesures ?
    Moi j'ai utilisé le module memory-profiler présent dans Pypi
    Voici mon code :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    @profile
    def my_test():
        import numpy
        a = numpy.arange(100000000.0)
     
    @profile
    def my_mem():
        print('fintest')
     
     
    print('debtest')
    my_test()
    my_mem()
    et voici le résultat :
    d:\dev\python\eric_env\scripts\python.exe -m memory_profiler testMemNumPy.py
    debtest
    fintest
    Filename: testMemNumPy.py


    Line # Mem usage Increment Occurences Line Contents
    ============================================================
    1 19.805 MiB 19.805 MiB 1 @profile
    2 def my_test():
    3 31.223 MiB 11.418 MiB 1 import numpy
    4 794.176 MiB 762.953 MiB 1 a = numpy.arange(100000000.0)




    Filename: testMemNumPy.py


    Line # Mem usage Increment Occurences Line Contents
    ============================================================
    6 31.234 MiB 31.234 MiB 1 @profile
    7 def my_mem():
    8 31.234 MiB 0.000 MiB 1 print('fintest')
    Ami calmant, J.P

  4. #4
    Membre éprouvé
    Homme Profil pro
    Vagabong étudiant en annalyse du signal.
    Inscrit en
    Avril 2019
    Messages
    127
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 26
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Vagabong étudiant en annalyse du signal.
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Avril 2019
    Messages : 127
    Par défaut
    Merci pour ces réponses.

    tant qu'il a des référence, il ne pourra pas être "détruit"
    C'est pour cela que j'ai d'abord utiliser "del" sur la variable référencée pour supprimer les références.
    Dans l'exemple que j'ai propose, quand on sort de la fonction "foo", la variable 'module' n'est plus référencée. Mais apparemment il reste une référence quelque part. Mais ou? Et comment aller supprimer cette référence cachée?

    Quel O.S et quelle version de python utilises-tu ?
    Je suis sur linux mint 64 bit, j'utilise python3.8.5, j'ai 2 Go de RAM et 120 Go de swap.

    Comment effectues-tu tes mesures ?
    Avec le "monitor-system" graphique de base. Quand je lance python à vide dans le terminal il prend 22.3 MiB, des que j'importe numpy il prend 387.3 MiB tandis qu'avec le module math par exemple, cela ne change pas.

    Je n'arrive pas à exécuter votre code, voici le résultat:
    >>> my_test()
    ERROR: Could not find file <stdin>
    >>> my_mem()
    ERROR: Could not find file <stdin>
    fintest
    >>>

  5. #5
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 679
    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 679
    Par défaut
    Salut,

    Citation Envoyé par robinechuca Voir le message
    Dans l'exemple que j'ai propose, quand on sort de la fonction "foo", la variable 'module' n'est plus référencée. Mais apparemment il reste une référence quelque part. Mais ou? Et comment aller supprimer cette référence cachée?
    Compter les références....
    Sinon cherchez un peu sur Internet, vous tomberiez sur des articles comme celui-ci qui vous montrent que ce n'est pas si simple.

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

  6. #6
    Expert confirmé
    Avatar de jurassic pork
    Homme Profil pro
    Bidouilleur
    Inscrit en
    Décembre 2008
    Messages
    4 181
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Bidouilleur
    Secteur : Industrie

    Informations forums :
    Inscription : Décembre 2008
    Messages : 4 181
    Par défaut
    hello,
    Citation Envoyé par robinechuca Voir le message
    Je n'arrive pas à exécuter votre code,
    c'est bizarre car je viens d'essayer le code sous ubuntu 20.04 et cela fonctionne. Mint est basé sur Ubuntu. J'ai installé memory-profiler par pip. A noter que l'on voit des >>> sur le résultat de ta commande comme si tu utilisais l'interpréteur et pas le lancement par la commande python avec le nom du fichier.
    Voici ce que j'obtiens quand je lance la commande dans un terminal :
    lcm@lcm-Desktop:~$ python3 --version
    Python 3.8.5
    lcm@lcm-Desktop-:~$ lsb_release -a
    No LSB modules are available.
    Distributor ID: Ubuntu
    Description: Ubuntu 20.04.1 LTS
    Release: 20.04
    Codename: focal
    lcm@lcm-Desktop-:~$ python3 -m memory_profiler testMemNumPy.py
    debtest
    fintest
    Filename: testMemNumPy.py


    Line # Mem usage Increment Occurences Line Contents
    ============================================================
    1 18.281 MiB 18.281 MiB 1 @profile
    2 def my_test():
    3 32.625 MiB 14.344 MiB 1 import numpy
    4 795.910 MiB 763.285 MiB 1 a = numpy.arange(100000000.0)




    Filename: testMemNumPy.py


    Line # Mem usage Increment Occurences Line Contents
    ============================================================
    6 33.223 MiB 33.223 MiB 1 @profile
    7 def my_mem():
    8 33.223 MiB 0.000 MiB 1 print('fintest')




    lcm@lcm-Desktop:~$

    numpy occupe 14,344 Mo quand on le charge.


    Ami calmant, J.P

  7. #7
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 801
    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 801
    Billets dans le blog
    1
    Par défaut
    Bonjour
    Citation Envoyé par robinechuca Voir le message
    Je suis sur linux mint 64 bit
    Ah, mint. Il commence à faire parler de lui, avec de bons retours. Je l'ai téléchargé mais pas encore testé (version xfce)

    Citation Envoyé par robinechuca Voir le message
    j'utilise python3.8.5, j'ai 2 Go de RAM et 120 Go de swap.
    60 fois la RAM en espace de swap
    A une époque on conseillait 2x la ram. Maintenant certains préconisent 1x la ram (surtout pour un linux quoi). Tu veux faire tourner quoi avec 120Go de swap ? Flight Simulator 3D ???
    De toute façon 60x la ram c'est démesuré. Si ton OS passe tout son temps à swapper il ne travaille plus !!!

    Citation Envoyé par robinechuca Voir le message
    Je n'arrive pas à exécuter votre code, voici le résultat:
    Il faut le mettre dans un fichier "toto.py" et lancer la commande python3 -m memory_profile toto.py depuis le shell. Voici ce que ça donne chez-moi
    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
    17
    18
    19
    debtest
    fintest
    Filename: essai.py
     
    Line #    Mem usage    Increment  Occurences   Line Contents
    ============================================================
         1   18.477 MiB   18.477 MiB           1   @profile
         2                                         def my_test():
         3   31.859 MiB   13.383 MiB           1       import numpy
         4  794.750 MiB  762.891 MiB           1       a = numpy.arange(100000000.0)
     
     
    Filename: essai.py
     
    Line #    Mem usage    Increment  Occurences   Line Contents
    ============================================================
         6   32.012 MiB   32.012 MiB           1   @profile
         7                                         def my_mem():
         8   32.012 MiB    0.000 MiB           1       print('fintest')
    Donc 13.3Mo pour numpy. Et effectivement le module math (j'ai rajouté un test là dessus) ne fait pas monter la chose.

    Citation Envoyé par robinechuca Voir le message
    Avec le "monitor-system" graphique de base.
    Mouais. Lui il regarde tout ton OS, pas que ton code. Dans ce genre de tests, plus c'est affiné vers le code mieux cela vaut...
    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]

  8. #8
    Membre éprouvé
    Homme Profil pro
    Vagabong étudiant en annalyse du signal.
    Inscrit en
    Avril 2019
    Messages
    127
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 26
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Vagabong étudiant en annalyse du signal.
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Avril 2019
    Messages : 127
    Par défaut
    En exécutant depuis un fichier, cela fonctionne:
    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
    17
    18
    19
    20
     
    debtest
    Filename: test.py
     
    Line #    Mem usage    Increment  Occurences   Line Contents
    ============================================================
         3     17.3 MiB     17.3 MiB           1   @profile
         4                                         def my_test():
         5     31.6 MiB     14.3 MiB           1       import numpy
         6    794.9 MiB    763.3 MiB           1       a = numpy.arange(100000000.0)
     
     
    fintest
    Filename: test.py
     
    Line #    Mem usage    Increment  Occurences   Line Contents
    ============================================================
         8     32.1 MiB     32.1 MiB           1   @profile
         9                                         def my_mem():
        10     32.1 MiB      0.0 MiB           1       print('fintest')
    Effectivement vu d'ici numpy ne semble pas si consommateur que ça en RAM. Néanmoins, on remarque que 'a' est mangé par le ramasse miette mais pas 'numpy'. Ça confirme juste le problème, et ca montre qu'il est finalement pas si gros. Mais d’où peut venir cette différence de mémoire indiquée entre le monitor-system est ce que python crois utiliser? Je suis en ssh, peut-être que ça joue? Mais peut importe, disons que je souhaite a tout prix libérer les 14 Mo de numpy.

    En suivant le guide de 'wiztricks', je supprime aussi la référence cachée ici: "sys.modules["numpy"]"
    voici le resultat:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
         9                                         def my_mem():
        10     32.4 MiB      0.0 MiB           1       import sys
        11     32.4 MiB      0.0 MiB           1       del sys.modules["numpy"]
        12     32.4 MiB      0.0 MiB           1       print('fintest')
    Bref ça change rien, il y a toujours une référence de numpy quelque part...

    J'ai aussi essayé une solution très salle:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    >>> import importlib
    >>> import numpy
    >>> with open("numpy.py", "w") as f:
    ...     f.write("# module vide\n")
    ... 
    14
    >>> importlib.reload(numpy)
    Le problème persiste toujours!

    Tu veux faire tourner quoi avec 120Go de swap?
    Matlab avec ces fuites mémoire (record personnel de 80 Go de ram prise...), et des simulations avec python...
    ton OS passe tout son temps à swapper il ne travaille plus
    J'ai un disque plutôt rapide et un cpu tellement lent (intel centrino) que je perds environ un facteur 12 de vitesse seulement quand je swap. Je préfère laguer que planter.

    N'y aurait-il pas moyen d'importer numpy dans un environnement étanche, pour qu'il ne fasse pas des références dans tous les sens?

  9. #9
    Membre éprouvé
    Homme Profil pro
    Vagabong étudiant en annalyse du signal.
    Inscrit en
    Avril 2019
    Messages
    127
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 26
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Vagabong étudiant en annalyse du signal.
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Avril 2019
    Messages : 127
    Par défaut
    J'ai trouvé une semi-solution moche:
    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
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
     
    from memory_profiler import profile
    import sys
     
    class Importateur:
        def __init__(self, modulename):
            self.modulename = modulename
            self.old_refs = set(sys.modules.keys())
            self.module = __import__(self.modulename)
            self.new_refs = set(sys.modules.keys())
     
        def __enter__(self):
            return self.module
     
        def __exit__(self, *args):
            for modname in self.new_refs - self.old_refs:
                del sys.modules[modname]
     
    @profile
    def my_test():
        with Importateur("numpy") as numpy:
            a = numpy.arange(100000000.0)
     
    @profile
    def my_mem():
        print("termine")
     
    my_test()
    my_mem()
    Mais cela ne libère pas toute la mémoire prise et c'est risqué car si entre le __enter__ et le __exit__ un module est importé et qu'il utilise des références déjà présentes, il risque de planter plus tard... Pas top quoi!

Discussions similaires

  1. Ports utilisés par le module Import Wizard
    Par rfr14 dans le forum Administration-Migration
    Réponses: 2
    Dernier message: 10/02/2009, 15h27
  2. Réponses: 0
    Dernier message: 26/01/2009, 15h17
  3. Perte en cours de programme des modules importés
    Par bourgui78 dans le forum Général Python
    Réponses: 6
    Dernier message: 08/09/2008, 15h41
  4. Réponses: 2
    Dernier message: 06/09/2006, 22h04
  5. Module importer Feuil Excel
    Par beurnoir dans le forum Access
    Réponses: 2
    Dernier message: 05/12/2005, 15h06

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