Programmering

Sådan bruges cProfile til profilering af Python-kode

Python er måske ikke det hurtigste sprog, men det er ofte hurtigt nok. Og Python er ideel, når programmørtid betyder noget mere end CPU-tid.

Når det er sagt, hvis en given Python-app er laggy, er du ikke forpligtet til bare at suge den op. Værktøjer, der følger med lagerinstallationen af ​​Python-tolk, kan give dig detaljeret feedback om, hvilke dele af dit program der er langsomme, og give nogle tip om, hvordan du fremskynder dem.

Sådan bruges cProfile

Det cProfil modul samler statistik om udførelsestiden for et Python-program. Det kan rapportere om alt fra hele appen til et enkelt udsagn eller udtryk.

Her er et legetøjseksempel på, hvordan man bruger cProfil:

def tilføj (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) hvis __name__ == '__main__': import cProfile cProfile.run ('main ( ) ') 

Dette eksempel kører applikationens hoved () funktion og analyserer ydeevnen af hoved () og det hele hoved () opkald. Det er også muligt kun at analysere aen del af et program, men den mest almindelige anvendelse for startere er at profilere hele programmet.

Kør ovenstående eksempel, og du vil blive mødt med noget som følgende output:

Det, der vises her, er en liste over alle funktionskald foretaget af programmet sammen med statistik om hver:

  • Øverst (første linje i blåt) ser vi det samlede antal opkald foretaget i det profilerede program og den samlede udførelsestid. Du kan også se en figur for "primitive opkald", hvilket betyder ikke-rekursiv opkald eller opkald foretaget direkte til en funktion, der ikke igen kalder sig længere nede i opkaldstakken.
  • ncalls: Antal foretagne opkald. Hvis du ser to tal adskilt af en skråstreg, er det andet nummer antallet af primitive opkald til denne funktion.
  • heltid: Samlet tid brugt i funktionen, ikke inklusive opkald til andre funktioner.
  • percall: Gennemsnitlig tid pr. Opkald til heltid, afledt ved at tage heltid og dividere det med ncalls.
  • cumtime: Samlet tid brugt i funktionen inklusive opkald til andre funktioner.
  • percall (Nr. 2): Gennemsnitlig tid pr. Opkald til cumtime (cumtime divideret med ncalls).
  • filnavn: lineno: Filnavnet, linjenummeret og funktionsnavnet for det pågældende opkald.

Sådan ændres cProfile-rapporter

Som standard, cProfil sorterer dens output efter "standardnavn", hvilket betyder, at den sorterer efter teksten i kolonnen længst til højre (filnavn, linjenummer osv.).

Standardformatet er nyttigt, hvis du vil have en generel top-down-rapport af hvert enkelt funktionsopkald til reference. Men hvis du prøver at komme til bunden af ​​en flaskehals, vil du sandsynligvis have de mest tidskrævende dele af programmet, der er anført først.

Vi kan producere disse resultater ved at påberåbe oscProfil lidt anderledes. Bemærk, hvordan den nederste del af ovenstående program kan omarbejdes til at sortere statistikkerne efter en anden kolonne (i dette tilfælde 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 () 

Resultaterne vil se sådan ud:

Sådan fungerer alt dette:

  • I stedet for at udføre en kommando ved hjælp af cProfile.run (), som ikke er meget fleksibel, opretter vi en profilering objekt, profiler.
  • Når vi vil profilere nogle handlinger, ringer vi først .aktiver () på profilerobjektforekomsten, kør derefter handlingen, og ring derefter .disable (). (Dette er en måde at kun profilere en del af et program på.)
  • Det pstats modulet bruges til at manipulere de resultater, der indsamles af profilerobjektet og udskrive disse resultater.

Kombination af et profilobjekt og pstats giver os mulighed for at manipulere de fangede profildata - for eksempel at sortere de genererede statistikker forskelligt. I dette eksempel bruger du .sort_stats ('ncalls') sorterer statistikken efter ncalls kolonne. Andre sorteringsmuligheder er tilgængelige.

Sådan bruges cProfile-resultater til optimering

De tilgængelige sorteringsmuligheder for cProfil output giver os mulighed for at drille potentielle flaskehalse i et program.

ncalls

Det første og mest betydningsfulde stykke information, du kan finde ud af cProfil er hvilke funktioner der kaldes hyppigst ved hjælp af ncalls kolonne.

I Python medfører den blotte handling for at foretage et funktionsopkald relativt store omkostninger. Hvis en eller anden funktion kaldes gentagne gange i en tæt loop, selvom det ikke er en langvarig funktion, er det garanteret at påvirke ydeevnen.

I ovenstående eksempel funktion tilføje (og funktionen tilføj_2) kaldes gentagne gange i en løkke. Flytning af sløjfen ind i tilføje funktion i sig selv eller inline tilføje fungerer helt, ville løse dette problem.

heltid

En anden nyttig statistikdetaljer, som fungerer, programmet bruger det meste af sin tid på at udføre ved hjælp af heltid kolonne.

I ovenstående eksempel er tilføj_2 funktion bruger en sløjfe til at simulere nogle dyre beregninger, som skubber dens heltid score til toppen. Enhver funktion med en høj heltid score fortjener et nøje kig, især hvis det kaldes mange gange eller i en tæt loop.

Bemærk, at du altid skal overveje sammenhæng hvor funktionen bruges. Hvis en funktion har en høj heltid men kaldes kun en gang - for eksempel kun når programmet starter - er det mindre sandsynligt, at det er en flaskehals. Hvis du forsøger at reducere opstartstiden, vil du dog gerne vide, om en funktion, der kaldes ved opstart, får alt andet til at vente.

Sådan eksporteres cProfile-data

Hvis du vil bruge cProfilgenererede statistikker på mere avancerede måder, kan du eksportere dem til en datafil:

stats = pstats.Stats (profil) stats.dump_stats ('/ sti / til / stats_file.dat') 

Denne fil kan læses tilbage ved hjælp af pstats modul, derefter sorteret eller vist med pstats. Dataene kan også genbruges af andre programmer. To eksempler:

  • pyprof2calltree gengiver detaljerede visualiseringer af programmets opkaldsgraf og brugsstatistik ud fra profildata. Denne artikel giver et detaljeret eksempel fra den virkelige verden på dens anvendelse.
  • snakeviz genererer også visualiseringer fra cProfil data, men bruger en anden repræsentation for dataene - en "sunburst" snarere end pyprof2calltree's "flamme" -graf.

Beyond cProfile til Python-profilering

cProfil er næppe den eneste måde at profilere en Python-applikation på. cProfil er bestemt en af ​​de mest bekvemme måder, i betragtning af at den er pakket med Python. Men andre fortjener opmærksomhed.

Et projekt, py-spion, bygger en profil til en Python-applikation ved at prøve sin opkaldsaktivitet. py-spion kan bruges til at undersøge en kørende Python-app uden at skulle stoppe og genstarte den og uden at skulle ændre dens kodebase, så den kan bruges til at profilere implementerede applikationer. py-spion genererer også nogle statistikker om omkostningerne ved Python-runtime (for eksempel skraldesamlingskostnader), som cProfil gør ikke.