Python Language
Prestandaoptimering
Sök…
Anmärkningar
När du försöker förbättra prestandan för ett Python-skript bör du först och främst kunna hitta flaskhalsen i ditt skript och notera att ingen optimering kan kompensera för ett dåligt val i datastrukturer eller en fel i din algoritmdesign. Identifiera prestandaflaskhalsar kan göras genom att profilera ditt skript. För det andra, försök inte optimera för tidigt i din kodningsprocess på bekostnad av läsbarhet / design / kvalitet. Donald Knuth uttalade följande om optimering:
”Vi borde glömma från små effektiviteter, säga cirka 97% av tiden: för tidig optimering är roten till allt ont. Ändå ska vi inte överlämna våra möjligheter i de kritiska 3%. ”
Kodprofilering
Först och främst bör du kunna hitta flaskhalsen i ditt skript och notera att ingen optimering kan kompensera för ett dåligt val i datastrukturen eller en brist i din algoritmdesign. För det andra, försök inte optimera för tidigt i din kodningsprocess på bekostnad av läsbarhet / design / kvalitet. Donald Knuth uttalade följande om optimering:
"Vi borde glömma från små effektiviteter, säga cirka 97% av tiden: för tidig optimering är roten till allt ont. Men vi bör inte överlämna våra möjligheter i de kritiska 3%."
För att profilera din kod har du flera verktyg: cProfile
(eller den långsammare profile
) från standardbiblioteket, line_profiler
och timeit
. Var och en av dem tjänar ett annat syfte.
cProfile
är en determistisk profil: funktionssamtal, funktionsåtergång och undantagshändelser övervakas och exakta tidpunkter görs för intervall mellan dessa händelser (upp till 0,001s). Biblioteksdokumentationen ([ https://docs.python.org/2/library/profile.html????1]) ger oss ett fall med enkel användning
import cProfile
def f(x):
return "42!"
cProfile.run('f(12)')
Eller om du föredrar att lasta in delar av din befintliga kod:
import cProfile, pstats, StringIO
pr = cProfile.Profile()
pr.enable()
# ... do something ...
# ... long ...
pr.disable()
sortby = 'cumulative'
ps = pstats.Stats(pr, stream=s).sort_stats(sortby)
ps.print_stats()
print s.getvalue()
Detta skapar utgångar som ser ut som i tabellen nedan, där du snabbt kan se var ditt program tillbringar större delen av sin tid och identifiera de funktioner som ska optimeras.
3 function calls in 0.000 seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.000 0.000 0.000 0.000 <stdin>:1(f)
1 0.000 0.000 0.000 0.000 <string>:1(<module>)
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
Modulen line_profiler
([ https://github.com/rkern/line_profiler????1]) är användbar för att ha en rad för radanalys av din kod. Detta är uppenbarligen inte hanterbart för långa skript utan riktar sig till utdrag. Se dokumentationen för mer information. Det enklaste sättet att komma igång är att använda kernprof-skriptet, som förklaras på paketets sida. Observera att du måste ange manuellt funktion (er) för profil.
$ kernprof -l script_to_profile.py
kernprof skapar en instans av LineProfiler och infogar den i __builtins__
namnutrymme med __builtins__
. Det har skrivits för att användas som dekoratör, så i ditt skript dekorerar du de funktioner du vill profilera med @profile
.
@profile
def slow_function(a, b, c):
...
Standardprocessen för kernprof är att lägga resultaten i en binär fil script_to_profile.py.lprof
. Du kan säga kernprof att omedelbart visa de formaterade resultaten vid terminalen med alternativet [-v / - view]. Annars kan du se resultaten senare så:
$ python -m line_profiler script_to_profile.py.lprof
Slutligen ger timeit
ett enkelt sätt att testa ett foder eller ett litet uttryck både från kommandoraden och pythonskalet. Den här modulen kommer att besvara frågor som, är det snabbare att göra en listaförståelse eller använda den inbyggda list()
när du omvandlar en uppsättning till en lista. Leta efter setup
sökord eller -s
möjlighet att lägga inställningskoden.
>>> import timeit
>>> timeit.timeit('"-".join(str(n) for n in range(100))', number=10000)
0.8187260627746582
från en terminal
$ python -m timeit '"-".join(str(n) for n in range(100))'
10000 loops, best of 3: 40.3 usec per loop