Comme il y a plus d’une façon de faire en Python, trouver l’approche la plus efficace en termes de mémoire pour certaines tâches peut s’avérer difficile. C’est là qu’un profileur de mémoire peut être utile. En plus de traquer les fuites, l’estimation du profil mémoire de votre code permet de déterminer quel code est efficace en termes de mémoire.
Que vous développiez un modèle d’apprentissage automatique ou un site web avec Python, vous pouvez estimer le profil de mémoire des scripts, des lignes de code individuelles ou des fonctions.
Quelques outils pour estimer le profil de mémoire en Python
Estimer le profil mémoire de l’ensemble de votre base de code peut s’avérer peu pratique, car cela peut ralentir votre application de manière significative. Il est préférable de profiler sélectivement les fonctions ou les méthodes que vous soupçonnez de consommer plus de mémoire. Mais même si vous voulez faire cela pour l’ensemble de votre application, vous pourriez vouloir dédier un module isolé à cette tâche.
Il existe de nombreuses bibliothèques de profilage en Python. Les plus populaires sont memory_profiler, psutil, Tracemallocet pympler. Ce tutoriel utilise memory_profiler et psutil.
Tandis que psutil est idéal pour estimer la consommation totale de mémoire lors de l’exécution d’une méthode ou d’une fonction, memory_profiler fournit des informations plus détaillées sur l’utilisation de la mémoire, y compris les tendances d’utilisation ligne par ligne et au niveau fonctionnel.
Pour commencer, installez memory_profiler dans votre environnement virtuel Python. Ceci installe également psutil.
pip install memory_profiler
Obtenir la taille d’un objet en mémoire
Vous pouvez commencer votre profilage de la mémoire en calculant d’abord la taille d’un objet que vous avez l’intention d’utiliser en mémoire.
Ce type de profilage est utile au début du développement, lorsqu’il s’agit de déterminer le type d’objet à utiliser dans un programme.
Par exemple, si vous n’arrivez pas à décider quelles méthodes utiliser pour accomplir une tâche, par exemple le type de données Python approprié, vous pouvez obtenir la taille de chacune en octets afin de déterminer laquelle est la plus légère pour votre cas d’utilisation.
Le sys.getsizeof La méthode intégrée est très utile ici :
import sys
print(f"list size: {sys.getsizeof([])} bytes")
print(f"dictionary size: {sys.getsizeof(dict)} bytes")
print(f"tuple size: {sys.getsizeof(())} bytes")
print(f"set size: {sys.getsizeof({})} bytes")
Voici le résultat :
Vous pouvez également utiliser la fonction sys.getsizeof pour comparer la taille de la mémoire d’une fonction intégrée et d’une fonction personnalisée.
Par exemple, comparez cette fonction de longueur personnalisée qui utilise une boucle for Python avec la fonction intégrée len fonction :
import sys
def getLength(iterable):
count = 0
for i in iterable:
count +=1
return count
print(f"Built-in length function: {sys.getsizeof(len)} bytes")
print(f"Custom length function: {sys.getsizeof(getLength)} bytes")
Le code ci-dessus donne le résultat suivant :
Cependant, alors que les sys.getsizeof mesure la taille d’un objet en mémoire, mais elle ne tient compte que de l’objet lui-même et non de ceux qui y font référence. Pour cela, vous aurez besoin d’une méthode de profilage plus détaillée.
Trouver le profil mémoire d’une fonction Python
Vous pouvez obtenir un profil de mémoire plus détaillé de chaque ligne de code d’une fonction en utilisant la fonction memory_profiler . Il s’agit d’ajouter l’élément @profil à votre fonction ou méthode :
import pandas
import numpy
from memory_profiler import profile
class Manipulate:
@profile
def manipulateData(self):
df = pandas.DataFrame({
'A' :[0, 3, numpy.nan, 10, 3, numpy.nan],
'B' : [numpy.nan, "Pandas", numpy.nan, "Pandas", "Python", "JavaScript"],
})
df.fillna(method='bfill', inplace=True)
df.fillna(method='ffill', inplace=True)
return str(df)
manip = Manipulate()
print(manip.manipulateData())
Le code ci-dessus donne un profil détaillé de la mémoire de chaque ligne de code dans la fonction, comme indiqué :
Le Utilisation de la mémoire indique l’utilisation de la mémoire pour une ligne de code particulière, tandis que la colonne Incrément montre la contribution de chaque ligne aux frais généraux. La colonne Occurrence La colonne Occurrence définit le nombre de fois qu’une ligne de code alloue ou désalloue de la mémoire.
Par exemple, dans la sortie ci-dessus, la ligne 11 est apparue deux fois avec un incrément de mémoire de 0,1 MiB (Mebibyte), augmentant l’utilisation de la mémoire à 55,4 MiB. Les lignes 19 et 22 ont également contribué à hauteur de 0,2 Mio et 0,3 Mio, respectivement, ce qui porte l’utilisation totale de la mémoire à 55,9 Mio.
Trouver le profil mémoire d’un script Python par horodatage
Vous pouvez également estimer le profil de mémoire d’un script Python entier à l’aide de la fonction memory_profiler en exécutant la commande mprof dans le terminal comme indiqué :
mprof run script_name.py
La commande ci-dessus échantillonne le script spécifié toutes les 0,1s et crée automatiquement un fichier .dat dans le répertoire de votre projet actuel.
Les figures qui suivent le MEM sont les profils d’utilisation de la mémoire du script Python à un intervalle de temps spécifique. Les derniers chiffres à droite représentent l’horodatage capturé par le profileur pour chaque utilisation de la mémoire.
Vous pouvez également obtenir un graphique du profil de mémoire. Cela nécessite l’installation de matplotlib:
pip install matplotlib
Une fois installé, exécutez le programme mprof comme suit :
mprof plot
Voici le résultat dans ce cas :
Exécuter le profil de mémoire du script dans un fichier Python dédié
Vous pouvez souhaiter établir un profil pour différents scripts Python. Vous pouvez le faire en utilisant un module Python dédié via la fonction sous-processus.
De cette façon, vous pouvez séparer votre profileur de mémoire de votre base de code et sauvegarder la sortie du graphique localement :
import subprocess
subprocess.run([
'mprof', 'run', '--include-children', 'missing.py'
])
# save the plot output locally
subprocess.run(['mprof', 'plot', '--output=output.jpg'])
Pour exécuter le profil de mémoire du script, il vous suffit d’exécuter le fichier Python contenant le code ci-dessus. Cela génère un graphique de profil de mémoire (sortie.jpg) dans le répertoire de fichiers :
Trouver la quantité de mémoire utilisée lors de l’exécution d’une fonction
Vous pouvez connaître le profil de mémoire total d’une méthode ou d’une fonction pendant son exécution à l’aide de la fonction psutil paquet.
Par exemple, pour profiler la méthode de manipulation Pandas DataFrame précédente dans un autre fichier Python :
import psutil
import sys
import os
sys.path.append(sys.path[0] + "/..")
# import the class containing your method
from somecode.missing import Manipulate
# instantiate the class
manip = Manipulate()
process = psutil.Process(os.getpid())
initial_memory = process.memory_info().rss
# run the target method:
manip.manipulateData()
# get the memory information after execution
final_memory = process.memory_info().rss
memory_consumed = final_memory - initial_memory
memory_consumed_mb = memory_consumed / (1024 * 1024)
print(f"Memory consumed by the function: {memory_consumed_mb:.2f} MB")
Le tableau ci-dessus estime le profil mémoire total de la méthode en mégaoctets (Mo), comme indiqué :
Trouver le profil de mémoire d’une ligne de code dans Jupyter Notebook
Si vous utilisez iPython dans Jupyter Notebook, vous pouvez calculer le profil de mémoire d’une ligne de code à l’aide de la fonction memory_profiler. Il suffit de charger memory_profiler dans une cellule. Ajoutez ensuite le %memit fonction magique à votre code dans les cellules suivantes ; elle renvoie la mémoire maximale du code et sa taille incrémentée.
Cette méthode ne fonctionne pas avec les scripts Python ordinaires en dehors de iPython dans Jupyter Notebook.
Par exemple :
Vous pouvez également utiliser l’option %memit Fonction magique du Bloc-notes de Jypyter permettant de profiler la mémoire d’une fonction au moment de l’exécution :
Améliorez l’efficacité de votre mémoire dans votre code Python
Compte tenu des tâches lourdes de collecte de données pour lesquelles nous utilisons souvent Python, chaque ligne de code a besoin d’une optimisation adéquate pour gérer l’utilisation de la mémoire. Bien que Python propose de nombreuses fonctions intégrées, les objets non référencés entraînent des fuites de mémoire.
Si vous avez intégré toutes les syntaxes Python qui fonctionnent dans votre base de code sans tenir compte de l’utilisation de la mémoire, vous devriez peut-être revenir en arrière avant d’aller trop loin.