Använd dessa tips för att analysera din kod och upptäcka var den är mest eller minst effektiv.

Eftersom "det finns mer än ett sätt att göra det" i Python, kan det vara en utmaning att hitta den mest minneseffektiva metoden för vissa uppgifter. Det är här en minnesprofilerare kan hjälpa till. Förutom att spåra läckor hjälper en uppskattning av din kods minnesprofil att avgöra vilken kod som är minneseffektiv.

Oavsett om du utvecklar en maskininlärningsmodell eller en webbplats med Python kan du uppskatta minnesprofilen för skript, individuella kodlinjer eller funktioner.

Att uppskatta minnesprofilen för hela din kodbas kan vara opraktisk, eftersom det kan sakta ner din applikation avsevärt. Det är bäst att du selektivt profilerar funktioner eller metoder som du misstänker kan förbruka mer minne istället. Men även om du vill göra detta för hela din applikation, kanske du vill dedikera en isolerad modul för att hantera det.

Det finns många profileringsbibliotek i Python. Några av de mest populära är

instagram viewer
memory_profiler, psutil, Tracemalloc, och pimpler. Denna handledning använder memory_profiler och psutil.

Medan psutil är idealisk för att uppskatta den totala minnesförbrukningen för en metod eller funktionsexekvering, memory_profiler ger mer detaljerad information om minnesanvändning, inklusive rad-för-för- och funktionstrender över tid.

För att börja, installera memory_profiler i din virtuella Python-miljö. Detta installerar också psutil.

pip installera memory_profiler

Få storleken på ett objekt i minnet

Du kan starta din minnesprofilering genom att först beräkna storleken på ett objekt som du tänker använda i minnet.

Den här typen av profilering är till hjälp i början av utvecklingen – samtidigt som man försöker bestämma vilken objekttyp som ska användas i ett program.

Om du till exempel fastnar för att bestämma vilka metoder du ska använda för att utföra en uppgift, säg, Python-datatyp, du kan få storleken på var och en i byte för att avgöra vilken som är lättare för din användning fall.

De sys.getsizeof den inbyggda metoden är praktisk här:

importera sys
skriva ut(f" liststorlek: {sys.getsizeof([])} bytes")
skriva ut(f" ordbok storlek: {sys.getsizeof (dict)} bytes")
skriva ut(f" tuppel storlek: {sys.getsizeof(())} bytes")
skriva ut(f"set storlek: {sys.getsizeof({})} byte")

Här är utgången:

Du kan också använda sys.getsizeof metod för att jämföra minnesstorleken för en inbyggd och anpassad funktion.

Jämför till exempel den här anpassade längdfunktionen som använder en Python för loop med det inbyggda len fungera:

importera sys

defgetLength(iterbar):
räkna = 0

för i i iterable:
räkna +=1

lämna tillbaka räkna

skriva ut(f"Inbyggd längdfunktion: {sys.getsizeof (len)} bytes")
skriva ut(f" Funktion för egen längd: {sys.getsizeof (getLength)} bytes")

Koden ovan ger följande utdata:

Men medan sys.getsizeof mäter ett objekts storlek i minnet, det tar bara hänsyn till själva objektet och inte de som refererar till det. För det behöver du en mer detaljerad profileringsmetod.

Hitta minnesprofilen för en Python-funktion

Du kan få en mer detaljerad minnesprofil för varje kodrad i en funktion med hjälp av memory_profiler paket. Detta innebär att lägga till @profil dekoratör till din funktion eller metod:

importera pandor
importera numpy
från memory_profiler importprofil

klassmanipulera:
@profil
def manipulateData (själv):
df = pandor. 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 = Manipulera()
print (manip.manipulateData())

Ovanstående kod ger en detaljerad minnesprofil för varje kodrad i funktionen som visas:

De Mem användning kolumnen anger minnesanvändningen för en viss kodrad, medan Ökning kolumnen visar de omkostnader som varje rad bidrar med. De Förekomst kolumnen definierar antalet gånger en kodrad allokerar eller avallokerar minne.

Till exempel, i utgången ovan, inträffade linje 11 två gånger med ett minnesökning på 0,1 MiB (Mebibyte), vilket ökade minnesanvändningen till 55,4 MiB. Linjerna 19 och 22 bidrog också med 0,2 MiB respektive 0,3 MiB, vilket sammanlagt minskade minnesanvändningen till 55,9 MiB.

Hitta minnesprofilen för ett Python-skript med tidsstämpel

Du kan också uppskatta minnesprofilen för ett helt Python-skript med hjälp av memory_profiler genom att köra mprof kommando i terminalen som visas:

mpof kör script_name.py

Ovanstående kommando samplar det angivna skriptet var 0.1:a och skapar automatiskt en .dat fil i din nuvarande projektkatalog.

Siffrorna som följer MEM notation är minnesanvändningsprofilerna för Python-skriptet vid ett specifikt tidsintervall. De sista siffrorna till höger representerar tidsstämpeln som profileraren fångade för varje minnesanvändning.

Du kan också få en plot av minnesprofilen. Detta kräver en installation av matplotlib:

pip installera matplotlib

När det är installerat, kör mprof kommando så här:

mpr tomt

Här är resultatet i det här fallet:

Kör skriptminnesprofilen i en dedikerad Python-fil

Du kanske vill profilera för olika Python-skript. Du kan göra det här med en dedikerad Python-modul via Python's delprocess.

På så sätt kan du separera din minnesprofilerare från din kodbas och spara grafutdata lokalt:

importera delprocess

subprocess.run([
'mprof', 'springa', '--inkludera-barn', "missing.py"
])

# spara plot-utdata lokalt
subprocess.run(['mprof', 'komplott', '--output=output.jpg'])

För att köra skriptets minnesprofil behöver du bara köra Python-filen som innehåller ovanstående kod. Detta genererar en minnesprofilplot (output.jpg) i filkatalogen:

Hitta mängden minne som används från en funktionsexekvering

Du kan hitta den totala minnesprofilen för en metod eller funktion under exekvering med hjälp av psutil paket.

Till exempel för att profilera det föregående Pandas DataFrame-manipulation metod i en annan Python-fil:

importera psutil
importera sys
importera os
sys.path.append (sys.path[0] + "/..")

# importera klassen som innehåller din metod
från någon kod.saknas importera Manipulera

# instansiera klassen
manip = Manipulera()

process = psutil. Process (os.getpid())
initial_memory = process.memory_info().rss

# kör målmetoden:
manip.manipulateData()

# få minnesinformationen efter exekvering
final_memory = process.memory_info().rss
memory_consumed = final_memory - initial_memory
memory_consumed_mb = memory_consumed / (1024 * 1024)
skriva ut(f"Minne som förbrukas av funktionen: {memory_consumed_mb:.2f} MB")

Ovanstående uppskattar den totala minnesprofilen för metoden i megabyte (MB) som visas:

Hitta minnesprofilen för en kodlinje i Jupyter Notebook

Om du använder iPython i Jupyter Notebook kan du beräkna minnesprofilen för en one-liner med hjälp av memory_profiler. Du behöver bara ladda memory_profiler i en cell. Lägg sedan till %memit magisk funktion till din kod i efterföljande celler; detta returnerar kodens toppminne och ökade storlek.

Den här metoden fungerar inte med vanliga Python-skript förutom iPython i Jupyter Notebook.

Till exempel:

Du kan också använda %memit magisk funktion i Jypyter Notebook för att profilera en funktions minne vid körning:

Förbättra din minneseffektivitet i din Python-kod

Med tanke på de tunga datalyftuppgifter vi ofta använder Python för, behöver varje kodrad adekvat optimering för att hantera minnesanvändning. Även om Python har många inbyggda Python-funktioner, resulterar objekt utan referens i minnesläckor.

Om du har tappat varje Python-syntax som fungerar i din kodbas utan att tänka på minnesanvändning, kanske du vill titta tillbaka innan du går för långt.