Python-skriptien optimointi tehokkuuden parantamiseksi

Python Skriptien Optimointi Tehokkuuden Parantamiseksi



Python-komentosarjojen optimointi suorituskyvyn parantamiseksi edellyttää koodimme pullonkaulojen tunnistamista ja korjaamista, mikä saa koodin toimimaan nopeammin ja tehokkaammin. Python on suosittu ja tehokas ohjelmointikieli, jota käytetään nykyään lukuisissa sovelluksissa, mukaan lukien data-analyysi, ML-projektit (koneoppiminen), verkkokehitys ja monet muut. Python-koodin optimointi on strategia, jolla parannetaan kehittäjäohjelman nopeutta ja tehokkuutta suoritettaessa mitä tahansa toimintaa käyttämällä vähemmän koodirivejä, vähemmän muistia tai lisäresursseja. Suuri ja tehoton koodi voi hidastaa ohjelman toimintaa, mikä voi johtaa huonoon asiakastyytyväisyyteen ja mahdollisiin taloudellisiin menetyksiin tai vaatia lisätyötä korjaamiseksi ja vianmäärittämiseksi.

Se on tarpeen tehtäessä tehtävää, joka vaatii useiden toimintojen tai tietojen käsittelyä. Siksi joidenkin tehottomien koodilohkojen ja toimintojen poistaminen ja parantaminen voi saada uskomattomia tuloksia, kuten seuraavat:

  1. Paranna sovelluksen suorituskykyä
  2. Luo luettava ja järjestetty koodi
  3. Tee virheiden valvonnasta ja virheenkorjauksesta yksinkertaisempaa
  4. Säästä huomattavasti laskentatehoa ja niin edelleen

Profiloi koodisi

Ennen kuin aloitamme optimoinnin, on tärkeää tunnistaa projektikoodin osat, jotka hidastavat sitä. Pythonin profiloinnin tekniikoita ovat cProfile ja profiilipaketit. Käytä tällaisia ​​työkaluja arvioidaksesi, kuinka nopeasti tietyt toiminnot ja koodirivit suoritetaan. cProfile-moduuli tuottaa raportin, joka kertoo kuinka kauan kunkin komentosarjafunktion suorittaminen kestää. Tämä raportti voi auttaa meitä löytämään kaikki hitaasti toimivat toiminnot, jotta voimme parantaa niitä.







Koodikatkelma:



tuonti cProfiili kuten cP
def laske summa ( inputNumber ) :
syötettyjen_lukujen_summa = 0
sillä aikaa inputNumber > 0 :
syötettyjen_lukujen_summa + = inputNumber % 10
inputNumber // = 10
Tulosta ( 'Syötenumeron kaikkien numeroiden summa on: 'syötenumeroiden_summa'' )
palata syötettyjen_lukujen_summa
def main_func ( ) :
cP. juosta ( 'calculateSum(9876543789)' )
jos __nimi__ == '__main__' :
main_func ( )

Ohjelma tekee yhteensä viisi funktiokutsua, kuten tulosteen ensimmäisellä rivillä näkyy. Kunkin funktiokutsun tiedot näkyvät seuraavilla muutamalla rivillä, mukaan lukien kuinka monta kertaa toimintoa on käynnistetty, funktion kokonaiskesto, puhelun kesto ja funktion kokonaisaika (mukaan lukien kaikki toiminnot, joita sitä kutsutaan).



Lisäksi ohjelma tulostaa kehotenäytölle raportin, joka osoittaa, että ohjelma suorittaa kaikkien tehtäviensä suoritusajan 0,000 sekunnissa. Tämä osoittaa, kuinka nopea ohjelma on.





Valitse oikea tietorakenne

Suorituskykyominaisuudet riippuvat tietorakenteesta. Erityisesti sanakirjat ovat nopeampia hakuja varten kuin yleiskäyttöistä tallennusta koskevat luettelot. Valitse tietorakenne, joka soveltuu parhaiten tiedoillasi suoritettaviin toimintoihin, jos tiedät ne. Seuraava esimerkki tutkii eri tietorakenteiden tehokkuutta identtiselle prosessille sen määrittämiseksi, onko tietorakenteessa jokin elementti olemassa.



Arvioimme ajan, joka kuluu sen tarkistamiseen, onko kussakin tietorakenteessa elementti – luettelo, joukko ja sanakirja – ja vertaamme niitä.

OptimizeDataType.py:

tuonti Timei kuten tt
tuonti satunnainen kuten rndobj
# Luo luettelo kokonaisluvuista
random_data_list = [ rndobj. randint ( 1 , 10 000 ) varten _ sisään alue ( 10 000 ) ]
# Luo sarja samoista tiedoista
random_data_set = aseta ( random_data_list )

# Luo sanakirja samoilla tiedoilla kuin avaimet
obj_DataDictionary = { yhdellä: Ei mitään varten yhdellä sisään random_data_list }

# Haettava elementti (olemassa tiedoissa)
satunnainen_löytettävä_luku = rndobj. valinta ( random_data_list )

# Mittaa aika tarkistaaksesi jäsenyys luettelossa
lista_aika = tt. Timei ( lambda : satunnainen_löytettävä_luku sisään random_data_list , määrä = 1000 )

# Mittaa aika sarjan jäsenyyden tarkistamiseen
Asettaa aika = tt. Timei ( lambda : satunnainen_löytettävä_luku sisään random_data_set , määrä = 1000 )

# Mittaa aika tarkistaaksesi jäsenyyden sanakirjasta
sanele_aika = tt. Timei ( lambda : satunnainen_löytettävä_luku sisään obj_DataDictionary , määrä = 1000 )

Tulosta ( f 'Luettelon jäsenyyden tarkistusaika: {list_time:.6f} sekuntia' )
Tulosta ( f 'Aseta jäsenten tarkistusaika: {set_time:.6f} sekuntia' )
Tulosta ( f 'Sanakirjan jäsenyyden tarkistusaika: {dict_time:.6f} sekuntia' )

Tämä koodi vertaa luetteloiden, joukkojen ja sanakirjojen suorituskykyä jäsentarkistuksia tehtäessä. Yleisesti ottaen joukot ja sanakirjat ovat huomattavasti nopeampia kuin jäsenyystestien luettelot, koska ne käyttävät hash-pohjaisia ​​hakuja, joten niiden keskimääräinen aikamonimutkaisuus on O(1). Listojen on toisaalta tehtävä lineaarisia hakuja, jotka johtavat O(n)-aikaisen monimutkaisuuden jäsenyystesteihin.

  Kuvakaappaus tietokoneesta Kuvaus luodaan automaattisesti

Käytä sisäänrakennettuja toimintoja silmukoiden sijaan

Pythonin lukuisia sisäänrakennettuja toimintoja tai menetelmiä voidaan käyttää suorittamaan tyypillisiä tehtäviä, kuten suodatusta, lajittelua ja kartoitusta. Näiden rutiinien käyttäminen silmukoiden luomisen sijaan auttaa nopeuttamaan koodia, koska ne on usein optimoitu suorituskyvyn mukaan.

Rakennetaan esimerkkikoodia, jolla voidaan verrata mukautettujen silmukoiden luomisen suorituskykyä käyttämällä tyypillisten töiden sisäänrakennettuja toimintoja (kuten map(), filter() ja sorted()). Arvioimme, kuinka hyvin eri kartoitus-, suodatus- ja lajittelumenetelmät toimivat.

BuiltInFunctions.py:

tuonti Timei kuten tt
# Esimerkkiluettelo numeroluettelosta
numbers_list = lista ( alue ( 1 , 10 000 ) )

# Funktio numeroiden_listan neliöön silmukan avulla
def square_using_loop ( numbers_list ) :
neliö_tulos = [ ]
varten yhdellä sisään numbers_list:
neliö_tulos. liittää ( yhdellä ** 2 )
palata neliö_tulos
# Toiminto suodattaa parilliset numerot_lista silmukan avulla
def filter_even_using_loop ( numbers_list ) :
filter_result = [ ]
varten yhdellä sisään numbers_list:
jos yhdellä % 2 == 0 :
filter_result. liittää ( yhdellä )
palata filter_result
# Toiminto numeroluettelon lajitteluun silmukan avulla
def sort_using_loop ( numbers_list ) :
palata lajiteltu ( numbers_list )
# Mittaa aika neliöimiseen numbers_list käyttämällä map()
kartta_aika = tt. Timei ( lambda : lista ( kartta ( lambda x: x ** 2 , numbers_list ) ) , määrä = 1000 )
# Mittaa aika parillisten lukujen_listan suodattamiseen käyttämällä filter()
suodatinaika = tt. Timei ( lambda : lista ( suodattaa ( lambda x: x % 2 == 0 , numbers_list ) ) , määrä = 1000 )
# Mittaa numeroluettelon lajitteluun käytetty aika lajittelemalla ()
lajiteltu_aika = tt. Timei ( lambda : lajiteltu ( numbers_list ) , määrä = 1000 )
# Mittaa aika neliöimiseen numbers_list käyttämällä silmukkaa
loop_map_time = tt. Timei ( lambda : square_using_loop ( numbers_list ) , määrä = 1000 )
# Mittaa aika parillisten numeroiden_listan suodattamiseen silmukan avulla
loop_filter_time = tt. Timei ( lambda : filter_even_using_loop ( numbers_list ) , määrä = 1000 )
# Mittaa aika, joka kuluu numeroluettelon lajitteluun silmukan avulla
loop_sorted_time = tt. Timei ( lambda : sort_using_loop ( numbers_list ) , määrä = 1000 )
Tulosta ( 'Numeroluettelo sisältää 10 000 elementtiä' )
Tulosta ( f 'Map() Aika: {map_time:.6f} sekuntia' )
Tulosta ( f 'Filter() Time: {filter_time:.6f} seconds' )
Tulosta ( f 'Lajiteltu() aika: {lajiteltu_aika:.6f} sekuntia' )
Tulosta ( f 'Silmukka (kartta) aika: {loop_map_time:.6f} sekuntia' )
Tulosta ( f 'Silmukka (suodatin) aika: {loop_filter_time:.6f} sekuntia' )
Tulosta ( f 'Silmukka (lajiteltu) aika: {loop_sorted_time:.6f} sekuntia' )

Todennäköisesti huomaamme, että sisäänrakennetut funktiot (map(), filter() ja sorted()) ovat nopeampia kuin näiden yleisten tehtävien mukautetut silmukat. Pythonin sisäänrakennetut toiminnot tarjoavat tiiviimmän ja ymmärrettävämmän lähestymistavan näiden tehtävien suorittamiseen ja ovat erittäin optimoituja suorituskykyä varten.

Optimoi silmukat

Jos silmukoiden kirjoittaminen on välttämätöntä, voimme nopeuttaa niitä muutamalla tekniikalla. Yleensä range()-silmukka on nopeampi kuin iterointi taaksepäin. Tämä johtuu siitä, että range() luo iteraattorin kääntämättä luetteloa, mikä voi olla kallis toimenpide pitkille listoille. Lisäksi, koska range() ei luo uutta luetteloa muistiin, se käyttää vähemmän muistia.

OptimizeLoop.py:

tuonti Timei kuten tt
# Esimerkkiluettelo numeroluettelosta
numbers_list = lista ( alue ( 1 , 100 000 ) )
# Toiminto toistaa luetteloa käänteisessä järjestyksessä
def silmukka_käänteinen_iteraatio ( ) :
tulos_käänteinen = [ ]
varten j sisään alue ( vain ( numbers_list ) - 1 , - 1 , - 1 ) :
tulos_käänteinen. liittää ( numbers_list [ j ] )
palata tulos_käänteinen
# Funktio toistaa luetteloa käyttämällä range()
def loop_range_iteration ( ) :
tulos_alue = [ ]
varten k sisään alue ( vain ( numbers_list ) ) :
tulos_alue. liittää ( numbers_list [ k ] )
palata tulos_alue
# Mittaa aika, joka kuluu käänteisen iteroinnin suorittamiseen
käänteinen_aika = tt. Timei ( silmukka_käänteinen_iteraatio , määrä = 1000 )
# Mittaa aika, joka kuluu etäisyyden iteroinnin suorittamiseen
range_time = tt. Timei ( loop_range_iteration , määrä = 1000 )
Tulosta ( 'Numeroluettelo sisältää 100 000 tietuetta' )
Tulosta ( f 'Käänteinen iteraatioaika: {reverse_time:.6f} sekuntia' )
Tulosta ( f 'Alueen iteraatioaika: {range_time:.6f} sekuntia' )

Vältä tarpeettomia toimintokutsuja

Joka kerta kun funktiota kutsutaan, on jonkin verran lisäkustannuksia. Koodi toimii nopeammin, jos tarpeettomat funktiokutsut vältetään. Esimerkiksi sen sijaan, että suoritat toistuvasti arvon laskevan funktion, yritä tallentaa laskutoimituksen tulos muuttujaan ja käyttää sitä.

Työkalut profilointiin

Saadaksesi lisätietoja koodisi toimivuudesta, voimme käyttää sisäänrakennetun profiloinnin lisäksi ulkoisia profilointipaketteja, kuten cProfile, Pyflame tai SnakeViz.

Välimuistin tulokset

Jos koodimme on suoritettava kalliita laskelmia, voimme harkita tulosten tallentamista välimuistiin ajan säästämiseksi.

Code Refaktorointi

Koodin muokkaaminen uudelleen luettavaksi ja ylläpidettäväksi on joskus välttämätön osa sen optimointia. Nopeampi ohjelma voi myös olla puhtaampi.

Käytä Just-in-Time -kokoelmaa (JIT)

PyPy- tai Numba-kirjastot voivat tarjota JIT-kokoelman, joka voi merkittävästi nopeuttaa tietyntyyppistä Python-koodia.

Päivitä Python

Varmista, että käytät Pythonin uusinta versiota, koska uudemmat versiot sisältävät usein suorituskyvyn parannuksia.

Rinnakkaisuus ja samanaikaisuus

Jos prosesseja voidaan rinnastaa, tutki rinnakkais- ja synkronointitekniikoita, kuten moniprosessointia, säikeistystä tai asynciota.

Muista, että benchmarkingin ja profiloinnin tulisi olla tärkeimmät optimoinnin tekijät. Keskity parantamaan koodimme alueita, joilla on merkittävin vaikutus suorituskykyyn, ja testaa jatkuvasti parannuksiasi varmistaaksesi, että niillä on halutut vaikutukset aiheuttamatta lisää vikoja.

Johtopäätös

Lopuksi Python-koodin optimointi on ratkaisevan tärkeää suorituskyvyn ja resurssitehokkuuden parantamiseksi. Kehittäjät voivat lisätä Python-sovellustensa suoritusnopeutta ja reagointikykyä huomattavasti käyttämällä erilaisia ​​tekniikoita, kuten sopivien tietorakenteiden valintaa, sisäänrakennettujen toimintojen hyödyntämistä, ylimääräisten silmukoiden vähentämistä ja muistin tehokasta hallintaa. Jatkuvan benchmarkingin ja profiloinnin pitäisi ohjata optimointiponnisteluja ja varmistaa, että koodin edistyminen vastaa todellisia suorituskykyvaatimuksia. Pitkän aikavälin projektin onnistumisen takaamiseksi ja uusien ongelmien syntymisen mahdollisuuden vähentämiseksi koodin optimointia tulisi jatkuvasti tasapainottaa koodin luettavuuden ja ylläpidettävyyden tavoitteiden kanssa.