Python er kanskje ikke det raskeste språket, men det er ofte raskt nok. Og Python er ideelt når programmererens tid betyr mer enn CPU-tid.
Når det er sagt, hvis en gitt Python-app er laggy, er du ikke forpliktet til å bare suge den opp. Verktøy som følger med lagerinstallasjonen av Python-tolken kan gi deg detaljert tilbakemelding om hvilke deler av programmet som er treg, og gi noen tips om hvordan du kan øke hastigheten på dem.
Hvordan bruke cProfile
De cProfil
modulen samler statistikk om kjøringstiden til et Python-program. Den kan rapportere om alt fra hele appen til et enkelt utsagn eller uttrykk.
Her er et leketøyeksempel på hvordan du bruker cProfil
:
def add (x, y): x + = str (y) return x def add_2 (x, y): hvis y% 20000 == 0: z = [] for q i området (0,400000): z.append ( q) def main (): a = [] for n i området (0,200000): add (a, n) add_2 (a, n) if __name__ == '__main__': import cProfile cProfile.run ('main ( ) ')
Dette eksemplet kjører applikasjonens hoved()
funksjon og analyserer ytelsen til hoved()
og alt hoved()
ringer. Det er også mulig å analysere bare adel av et program, men den vanligste bruken for det første er å profilere hele programmet.
Kjør eksemplet ovenfor, og du vil bli møtt med noe som følgende utgang:
Det som vises her er en liste over alle funksjonsanropene som er gjort av programmet, sammen med statistikk om hver:
- Øverst (første linje i blått) ser vi det totale antallet anrop som er gjort i det profilerte programmet og den totale gjennomføringstiden. Du kan også se en figur for "primitive samtaler", som betyr ikke-rekursiv samtaler eller anrop direkte til en funksjon som ikke i sin tur kaller seg lenger nede i samtalestakken.
- ncalls: Antall anrop. Hvis du ser to tall atskilt med en skråstrek, er det andre tallet antallet primitive anrop for den funksjonen.
- heltid: Total tid brukt i funksjonen, ikke inkludert samtaler til andre funksjoner.
- percall: Gjennomsnittlig tid per samtale for heltid, avledet ved å ta heltid og dele den med ncalls.
- cumtime: Total tid brukt i funksjonen, inkludert samtaler til andre funksjoner.
- percall (Nr. 2): Gjennomsnittlig tid per samtale for cumtime (cumtime delt på ncalls).
- filnavn: lineno: Filnavnet, linjenummeret og funksjonsnavnet for den aktuelle samtalen.
Slik endrer du cProfile-rapporter
Som standard, cProfil
sorterer utdataene etter "standardnavn", noe som betyr at den sorterer etter teksten i kolonnen lengst til høyre (filnavn, linjenummer osv.).
Standardformatet er nyttig hvis du vil ha en generell rapport ovenfra og ned av hver enkelt funksjon som kalles for referanse. Men hvis du prøver å komme til bunns i en flaskehals, vil du sannsynligvis ha de mest tidkrevende delene av programmet først.
Vi kan produsere disse resultatene ved å påkallecProfil
litt annerledes. Legg merke til hvordan den nederste delen av programmet ovenfor kan bearbeides for å sortere statistikken etter en annen kolonne (i dette tilfellet ncalls
):
hvis __name__ == '__main__': import cProfile, pstats profiler = cProfile.Profile () profiler.enable () main () profiler.disable () stats = pstats.Stats (profiler) .sort_stats ('ncalls') stats.print_stats ()
Resultatene vil se ut slik:
Slik fungerer alt dette:
- I stedet for å utføre en kommando i form av
cProfile.run ()
, som ikke er veldig fleksibel, lager vi en profilering gjenstand,profiler
. - Når vi vil profilere noe, ringer vi først
.muliggjøre()
på profilerobjektforekomsten, kjør deretter handlingen, og ring deretter.disable ()
. (Dette er en måte å bare profilere en del av et program på.) - De
pstats
modulen brukes til å manipulere resultatene som er samlet inn av profilobjektet og skrive ut resultatene.
Kombinere et profilobjekt og pstats
lar oss manipulere fangede profildata - for eksempel å sortere generert statistikk på en annen måte. I dette eksemplet bruker .sort_stats ('ncalls')
sorterer statistikken etter ncalls
kolonne. Andre sorteringsalternativer er tilgjengelige.
Hvordan bruke cProfile-resultater for optimalisering
Sorteringsalternativene som er tilgjengelige for cProfil
output gir oss muligheten til å plage ut potensielle ytelsesflaskehalser i et program.
ncalls
Den første og viktigste informasjonen du kan finne ut av cProfil
er hvilke funksjoner som ofte kalles, ved hjelp av ncalls
kolonne.
I Python pådrar det seg bare å utføre et funksjonsanrop relativt mye overhead. Hvis noen funksjoner kalles gjentatte ganger i en tett løkke, selv om det ikke er en langvarig funksjon, vil det garantert påvirke ytelsen.
I eksemplet ovenfor funksjonen legge til
(og funksjonen add_2
) kalles gjentatte ganger i en løkke. Flytter løkken inn i legge til
funksjonen i seg selv, eller inline legge til
fungerer helt, vil løse dette problemet.
heltid
En annen nyttig statistikk som funksjoner programmet bruker mesteparten av tiden på å utføre, i form av heltid
kolonne.
I eksemplet ovenfor er add_2
funksjonen bruker en sløyfe for å simulere noen dyre beregninger, som skyver dens heltid
scorer til toppen. Enhver funksjon med høy heltid
score fortjener en nøye titt, spesielt hvis den kalles mange ganger eller i en tett løkke.
Merk at du alltid må vurdere kontekst der funksjonen brukes. Hvis en funksjon har en høy heltid
men kalles bare én gang - for eksempel bare når programmet starter - det er mindre sannsynlig å være en flaskehals. Men hvis du prøver å redusere oppstartstiden, vil du vite om en funksjon som kalles ved oppstart, får alt annet til å vente.
Hvordan eksportere cProfile data
Hvis du vil bruke cProfil
generert statistikk på mer avanserte måter, kan du eksportere dem til en datafil:
stats = pstats.Stats (profiler) stats.dump_stats ('/ path / to / stats_file.dat')
Denne filen kan leses inn igjen ved å bruke pstats
modul, deretter sortert eller vist med pstats
. Dataene kan også brukes på nytt av andre programmer. To eksempler:
pyprof2calltree
gjengir detaljerte visualiseringer av programmets samtalediagram og bruksstatistikk fra profildata. Denne artikkelen gir et detaljert eksempel fra bruken av den virkelige verden.snakeviz
genererer også visualiseringer fracProfil
data, men bruker en annen representasjon for dataene - en "sunburst" i stedet for pyprof2calltree's "flamme" -graf.
Utover cProfile for Python-profilering
cProfil
er neppe den eneste måten å profilere et Python-program på. cProfil
er absolutt en av de mest praktiske måtene, gitt at den følger med Python. Men andre fortjener oppmerksomhet.
Ett prosjekt, py-spion
, bygger en profil for et Python-program ved å sampler samtaleaktiviteten. py-spion
kan brukes til å undersøke en kjørende Python-app uten å måtte stoppe og starte den på nytt, og uten å måtte endre kodebasen, slik at den kan brukes til å profilere distribuerte applikasjoner. py-spion
genererer også litt statistikk om overhead påløpt av Python runtime (for eksempel søppeloppsamling overhead), som cProfil
gjør ikke.