Sådan optimerer du dine Python-scripts for bedre ydeevne

Sadan Optimerer Du Dine Python Scripts For Bedre Ydeevne



At optimere Python-scripts for bedre ydeevne indebærer at identificere og adressere flaskehalsene i vores kode, så den kører hurtigere og mere effektivt. Python er et populært og kraftfuldt programmeringssprog, der bruges i adskillige applikationer i dag, herunder dataanalyse, ML-projekter (machine learning), webudvikling og mange flere. Python-kodeoptimering er en strategi til at forbedre udviklerprogrammets hastighed og effektivitet, når du udfører enhver aktivitet ved at bruge færre linjer kode, mindre hukommelse eller yderligere ressourcer. Stor og ineffektiv kode kan gøre programmet langsommere, hvilket kan resultere i dårlig kundetilfredshed og potentielt økonomisk tab eller behov for mere arbejde med at rette og fejlfinde.

Det er nødvendigt, mens du udfører en opgave, der kræver behandling af flere handlinger eller data. Derfor kan udskiftning og forbedring af nogle ineffektive kodeblokke og funktionaliteter have fantastiske resultater som følgende:

  1. Boost applikationens ydeevne
  2. Opret læsbar og organiseret kode
  3. Gør fejlovervågning og fejlfinding enklere
  4. Bevar betydelig regnekraft og så videre

Profilér din kode

Før vi begynder at optimere, er det vigtigt at identificere de dele af projektkoden, der bremser den. Teknikkerne til profilering i Python inkluderer cProfile- og profilpakkerne. Brug sådanne værktøjer til at måle, hvor hurtigt visse funktioner og kodelinjer udføres. cProfile-modulet producerer en rapport, der beskriver, hvor lang tid hver scriptfunktion tager at køre. Denne rapport kan hjælpe os med at finde alle funktioner, der kører langsomt, så vi kan forbedre dem.







Kodestykke:



importere cProfil som cP
def udregn Sum ( inputNumber ) :
sum_of_input_numre = 0
mens inputNumber > 0 :
sum_of_input_numbers + = inputNumber % 10
inputNumber // = 10
Print ( 'Summen af ​​alle cifre i inputnummer er: 'sum_of_input_numre'' )
Vend tilbage sum_of_input_numre
def main_func ( ) :
cP. løb ( 'beregnSum(9876543789)' )
hvis __navn__ == '__main__' :
main_func ( )

Programmet foretager i alt fem funktionskald, som det ses på første linje i outputtet. Detaljerne for hvert funktionskald er vist i de følgende få linjer, herunder antallet af gange, funktionen blev aktiveret, den samlede varighed af tid i funktionen, varigheden af ​​tid pr. opkald og den samlede tid i funktionen (inklusive alle de funktioner, det kaldes).



Derudover udskriver programmet en rapport på promptskærmen, som viser, at programmet fuldfører udførelsestiden for alle dets opgaver inden for 0.000 sekunder. Dette viser, hvor hurtigt programmet er.





Vælg den rigtige datastruktur

Ydeevnekarakteristika afhænger af datastrukturen. Især ordbøger er hurtigere til opslag end lister vedrørende den generelle lagring. Vælg den datastruktur, der er bedst egnet til de operationer, vi vil udføre på dine data, hvis du kender dem. Det følgende eksempel undersøger effektiviteten af ​​forskellige datastrukturer for en identisk proces for at bestemme, om et element i datastrukturen er til stede.



Vi evaluerer den tid, det tager at kontrollere, om et element er til stede i hver datastruktur – en liste, et sæt og en ordbog – og sammenligner dem.

OptimizeDataType.py:

importere Timei som tt
importere tilfældig som rndobj
# Generer en liste over heltal
random_data_list = [ rndobj. randint ( 1 , 10.000 ) til _ i rækkevidde ( 10.000 ) ]
# Opret et sæt ud fra de samme data
random_data_set = sæt ( random_data_list )

# Opret en ordbog med de samme data som nøgler
obj_DataDictionary = { på en: Ingen til på en i random_data_list }

# Element at søge efter (findes i dataene)
tilfældigt_tal_at_finde = rndobj. valg ( random_data_list )

# Mål tiden for at kontrollere medlemskab på en liste
liste_tid = tt. Timei ( lambda : tilfældigt_tal_at_finde i random_data_list , nummer = 1000 )

# Mål tiden for at kontrollere medlemskab i et sæt
fastsat tidspunkt = tt. Timei ( lambda : tilfældigt_tal_at_finde i random_data_set , nummer = 1000 )

# Mål tiden til at kontrollere medlemskab i en ordbog
dikt_tid = tt. Timei ( lambda : tilfældigt_tal_at_finde i obj_DataDictionary , nummer = 1000 )

Print ( f 'Tjektid for listemedlemskab: {list_time:.6f} sekunder' )
Print ( f 'Indstil medlemskabskontroltid: {set_time:.6f} sekunder' )
Print ( f 'Tjektid for ordbogsmedlemskab: {dict_time:.6f} sekunder' )

Denne kode sammenligner ydeevnen af ​​lister, sæt og ordbøger, når de udfører medlemskontrol. Generelt er sæt og ordbøger væsentligt hurtigere end lister til medlemskabstest, fordi de bruger hash-baserede opslag, så de har en gennemsnitlig tidskompleksitet på O(1). Lister skal derimod lave lineære søgninger, hvilket resulterer i medlemskabstest med O(n) tidskompleksitet.

  Et skærmbillede af en computer Beskrivelse genereret automatisk

Brug de indbyggede funktioner i stedet for løkker

Adskillige indbyggede funktioner eller metoder i Python kan bruges til at udføre typiske opgaver som filtrering, sortering og kortlægning. At bruge disse rutiner i stedet for at oprette ens loops hjælper med at fremskynde koden, fordi de ofte er præstationsoptimerede.

Lad os bygge noget eksempelkode for at sammenligne ydeevnen ved at skabe brugerdefinerede sløjfer ved at bruge de indbyggede funktioner til typiske job (såsom map(), filter() og sorteret()). Vi vil evaluere, hvor godt de forskellige kortlægnings-, filtrerings- og sorteringsmetoder fungerer.

BuiltInFunctions.py:

importere Timei som tt
# Eksempelliste over talliste
tal_liste = liste ( rækkevidde ( 1 , 10.000 ) )

# Funktion til square numbers_list ved hjælp af en loop
def square_using_loop ( tal_liste ) :
square_result = [ ]
til på en i tal_liste:
square_result. Tilføj ( på en ** 2 )
Vend tilbage square_result
# Funktion til at filtrere lige talsliste ved hjælp af en loop
def filter_even_using_loop ( tal_liste ) :
filter_result = [ ]
til på en i tal_liste:
hvis på en % 2 == 0 :
filter_result. Tilføj ( på en )
Vend tilbage filter_result
# Funktion til at sortere numbers_list ved hjælp af en loop
def sort_using_loop ( tal_liste ) :
Vend tilbage sorteret ( tal_liste )
# Mål tiden til square numbers_list ved hjælp af map()
kort_tid = tt. Timei ( lambda : liste ( kort ( lambda x: x ** 2 , tal_liste ) ) , nummer = 1000 )
# Mål tiden for at filtrere lige tal_liste ved hjælp af filter()
filter_tid = tt. Timei ( lambda : liste ( filter ( lambda x: x % 2 == 0 , tal_liste ) ) , nummer = 1000 )
# Mål tiden til at sortere numbers_list ved hjælp af sorted()
sorteret_tid = tt. Timei ( lambda : sorteret ( tal_liste ) , nummer = 1000 )
# Mål tiden til square numbers_list ved hjælp af en løkke
loop_map_time = tt. Timei ( lambda : square_using_loop ( tal_liste ) , nummer = 1000 )
# Mål tiden til at filtrere lige tal_liste ved hjælp af en løkke
loop_filter_time = tt. Timei ( lambda : filter_even_using_loop ( tal_liste ) , nummer = 1000 )
# Mål tiden til at sortere numbers_list ved hjælp af en løkke
sløjfesorteret_tid = tt. Timei ( lambda : sort_using_loop ( tal_liste ) , nummer = 1000 )
Print ( 'Nummerliste indeholder 10.000 elementer' )
Print ( f 'Map() Tid: {map_time:.6f} sekunder' )
Print ( f 'Filter() Tid: {filter_time:.6f} sekunder' )
Print ( f 'Sorteret() Tid: {sorteret_tid:.6f} sekunder' )
Print ( f 'Loop (kort) tid: {loop_map_time:.6f} sekunder' )
Print ( f 'Loop (Filter) Tid: {loop_filter_time:.6f} sekunder' )
Print ( f 'Sløjfe (sorteret) tid: {loop_sorted_time:.6f} sekunder' )

Vi vil sandsynligvis observere, at de indbyggede funktioner (map(), filter() og sorteret()) er hurtigere end de tilpassede sløjfer til disse almindelige opgaver. De indbyggede funktioner i Python tilbyder en mere kortfattet og forståelig tilgang til at udføre disse opgaver og er yderst optimeret til ydeevne.

Optimer løkkerne

Hvis det er nødvendigt at skrive løkkerne, er der et par teknikker, vi kan gøre for at fremskynde dem. Generelt er range()-løkken hurtigere end at gentage baglæns. Dette skyldes, at range() genererer en iterator uden at invertere listen, hvilket kan være en dyr operation for lange lister. Derudover, da range() ikke bygger en ny liste i hukommelsen, bruger den mindre hukommelse.

OptimizeLoop.py:

importere Timei som tt
# Eksempelliste over talliste
tal_liste = liste ( rækkevidde ( 1 , 100.000 ) )
# Funktion til at iterere over listen i omvendt rækkefølge
def loop_reverse_iteration ( ) :
resultat_omvendt = [ ]
til j i rækkevidde ( kun ( tal_liste ) - 1 , - 1 , - 1 ) :
resultat_omvendt. Tilføj ( tal_liste [ j ] )
Vend tilbage resultat_omvendt
# Funktion til at iterere over listen ved hjælp af range()
def loop_range_iteration ( ) :
resultatområde = [ ]
til k i rækkevidde ( kun ( tal_liste ) ) :
resultatområde. Tilføj ( tal_liste [ k ] )
Vend tilbage resultatområde
# Mål den tid, det tager at udføre omvendt iteration
omvendt_tid = tt. Timei ( loop_reverse_iteration , nummer = 1000 )
# Mål den tid, det tager at udføre interval iteration
range_time = tt. Timei ( loop_range_iteration , nummer = 1000 )
Print ( 'Nummerliste indeholder 100.000 poster' )
Print ( f 'Omvendt iterationstid: {reverse_time:.6f} sekunder' )
Print ( f 'Range Iteration Time: {range_time:.6f} sekunder' )

Undgå unødvendige funktionsopkald

Der er nogle overhead hver gang en funktion kaldes. Koden kører hurtigere, hvis unødvendige funktionskald undgås. For eksempel, i stedet for gentagne gange at udføre en funktion, der beregner en værdi, kan du prøve at gemme resultatet af beregningen i en variabel og bruge det.

Værktøjer til profilering

For at lære mere om ydeevnen af ​​din kode, udover indbygget profilering, kan vi bruge de eksterne profileringspakker som cProfile, Pyflame eller SnakeViz.

Cache resultater

Hvis vores kode skal udføre dyre beregninger, kan vi overveje at cache resultaterne for at spare tid.

Kode Refactoring

Refaktorering af koden for at gøre den nemmere at læse og vedligeholde er nogle gange en nødvendig del af optimering af den. Et hurtigere program kan også være renere.

Brug Just-in-Time Compilation (JIT)

Biblioteker som PyPy eller Numba kan levere en JIT-kompilering, som kan fremskynde visse typer Python-kode betydeligt.

Opgrader Python

Sørg for, at du bruger den nyeste version af Python, da nyere versioner ofte inkluderer ydeevneforbedringer.

Parallelisme og samtidighed

For processer, der kan paralleliseres, skal du undersøge parallel- og synkroniseringsteknikkerne som multiprocessing, threading eller asyncio.

Husk, at benchmarking og profilering bør være de vigtigste drivkræfter for optimering. Koncentrer dig om at forbedre de områder i vores kode, der har de mest signifikante effekter på ydeevnen, og test konstant dine forbedringer for at sikre, at de har de ønskede effekter uden at introducere flere defekter.

Konklusion

Som konklusion er Python-kodeoptimering afgørende for forbedret ydeevne og ressourceeffektivitet. Udviklere kan i høj grad øge udførelseshastigheden og reaktionsevnen af ​​deres Python-applikationer ved hjælp af forskellige teknikker, såsom at vælge de passende datastrukturer, udnytte de indbyggede funktioner, reducere de ekstra loops og effektivt styre hukommelsen. Kontinuerlig benchmarking og profilering burde styre optimeringsindsatsen og sikre, at kodefremskridtene matcher de virkelige præstationskrav. For at garantere en langsigtet projektsucces og mindske chancen for at introducere nye problemer, bør optimering af koden konstant balanceres med målene om kodelæsbarhed og vedligeholdelsesvenlighed.