Python-szkriptek optimalizálása a jobb teljesítmény érdekében

Python Szkriptek Optimalizalasa A Jobb Teljesitmeny Erdekeben



A Python-szkriptek jobb teljesítményű optimalizálása magában foglalja a kódunk szűk keresztmetszete azonosítását és megszüntetését, ezáltal gyorsabban és hatékonyabban fut. A Python egy népszerű és hatékony programozási nyelv, amelyet manapság számos alkalmazásban használnak, beleértve az adatelemzést, az ML projekteket (gépi tanulás), a webfejlesztést és még sok mást. A Python-kódoptimalizálás egy olyan stratégia, amely javítja a fejlesztői program sebességét és hatékonyságát, amikor kevesebb kódsort, kevesebb memóriát vagy további erőforrásokat használ fel. A nagy és nem hatékony kód lelassíthatja a programot, ami rossz ügyfél-elégedettséget és potenciális pénzügyi veszteséget okozhat, vagy további javítási és hibaelhárítási munkát igényelhet.

Ez több művelet vagy adat feldolgozását igénylő feladat elvégzése során szükséges. Ezért néhány nem hatékony kódblokk és funkció kikapcsolása és javítása csodálatos eredményeket hozhat, például a következőket:

  1. Növelje az alkalmazás teljesítményét
  2. Hozzon létre olvasható és rendezett kódot
  3. Tegye egyszerűbbé a hibafigyelést és a hibakeresést
  4. Takarítson meg jelentős számítási teljesítményt és így tovább

Profilozza meg kódját

Az optimalizálás megkezdése előtt elengedhetetlen, hogy azonosítsuk a projektkód azon részeit, amelyek lassítják azt. A Python profilalkotási technikái közé tartozik a cProfile és a profilcsomagok. Használja ezeket az eszközöket annak mérésére, hogy bizonyos függvények és kódsorok milyen gyorsan futnak le. A cProfile modul jelentést készít, amely részletezi, mennyi ideig tart az egyes parancsfájlok futtatása. Ez a jelentés segíthet megtalálni a lassan futó funkciókat, és javítani tudjuk azokat.







Kódrészlet:



import cProfile mint cP
def számítsa összeget ( inputNumber ) :
bemeneti_számok_összege = 0
míg inputNumber > 0 :
bemeneti_számok_összege + = inputNumber % 10
inputNumber // = 10
nyomtatás ( 'A bemeneti szám összes számjegyének összege: 'bemeneti_számok_összege'' )
Visszatérés bemeneti_számok_összege
def main_func ( ) :
cP. fuss ( 'calculateSum(9876543789)' )
ha __név__ == '__fő__' :
main_func ( )

A program összesen öt függvényhívást hajt végre, ahogy az a kimenet első sorában látható. Az egyes függvényhívások részletei a következő néhány sorban láthatók, beleértve a függvény meghívásának számát, a függvény teljes időtartamát, a hívásonkénti időtartamot és a függvény teljes időtartamát (beleértve az összes olyan függvény, amelyet ennek hívnak).



Ezenkívül a program egy jelentést nyomtat a prompt képernyőn, amely azt mutatja, hogy a program 0,000 másodpercen belül befejezi az összes feladat végrehajtási idejét. Ez mutatja, milyen gyors a program.





Válassza ki a megfelelő adatstruktúrát

A teljesítményjellemzők az adatszerkezettől függenek. Különösen a szótárak gyorsabbak a kereséshez, mint a listák az általános célú tárolással kapcsolatban. Válassza ki azt az adatstruktúrát, amely a legmegfelelőbb az adatokkal végzett műveletekhez, ha ezeket ismeri. A következő példa a különböző adatstruktúrák hatékonyságát vizsgálja egy azonos folyamathoz annak meghatározására, hogy az adatszerkezetben van-e elem.



Kiértékeljük, hogy mennyi időbe telik annak ellenőrzése, hogy egy elem megtalálható-e az egyes adatstruktúrákban – listában, halmazban és szótárban –, és összehasonlítjuk őket.

OptimizeDataType.py:

import Timei mint tt
import véletlen mint rndobj
# Készítsen egész számok listáját
random_data_list = [ rndobj. randint ( 1 , 10000 ) számára _ ban ben hatótávolság ( 10000 ) ]
# Hozzon létre egy halmazt ugyanazokból az adatokból
random_data_set = készlet ( random_data_list )

# Hozzon létre egy szótárt ugyanazokkal az adatokkal, mint a kulcsokkal
obj_DataDictionary = { az egyiken: Egyik sem számára az egyiken ban ben random_data_list }

# Keresendő elem (van az adatokban)
véletlen_keresendő_szám = rndobj. választás ( random_data_list )

# Mérje meg a listában való tagság ellenőrzéséhez szükséges időt
list_time = tt. Timei ( lambda : véletlen_keresendő_szám ban ben random_data_list , szám = 1000 )

# Mérje meg az időt a készlet tagságának ellenőrzéséhez
beállítani az időt = tt. Timei ( lambda : véletlen_keresendő_szám ban ben random_data_set , szám = 1000 )

# Mérje meg a szótári tagság ellenőrzéséhez szükséges időt
dict_time = tt. Timei ( lambda : véletlen_keresendő_szám ban ben obj_DataDictionary , szám = 1000 )

nyomtatás ( f 'Listatagság ellenőrzési ideje: {list_time:.6f} másodperc' )
nyomtatás ( f 'Tagságellenőrzési idő beállítása: {set_time:.6f} másodperc' )
nyomtatás ( f 'A szótári tagság ellenőrzési ideje: {dict_time:.6f} másodperc' )

Ez a kód összehasonlítja a listák, készletek és szótárak teljesítményét a tagságellenőrzés során. Általánosságban elmondható, hogy a készletek és szótárak lényegesen gyorsabbak, mint a tagsági tesztek listái, mivel hash-alapú kereséseket használnak, így átlagos időbonyolításuk O(1). A listáknak ezzel szemben lineáris keresést kell végezniük, ami O(n) időbonyolultságú tagsági teszteket eredményez.

  Képernyőkép egy számítógépről Leírás automatikusan generálva

Használja a beépített függvényeket hurkok helyett

A Python számos beépített függvénye vagy metódusa használható olyan tipikus feladatok elvégzésére, mint a szűrés, rendezés és leképezés. Ezeknek a rutinoknak a használata a hurkok létrehozása helyett segít felgyorsítani a kódot, mivel gyakran teljesítményoptimalizáltak.

Készítsünk néhány mintakódot, hogy összehasonlíthassuk az egyéni hurkok létrehozásának teljesítményét a tipikus feladatok beépített függvényeinek felhasználásával (mint például a map(), a filter() és a sorted()). Értékeljük, hogy a különböző térképezési, szűrési és válogatási módszerek mennyire teljesítenek jól.

BuiltInFunctions.py:

import Timei mint tt
# A numbers_list mintalistája
számok_lista = lista ( hatótávolság ( 1 , 10000 ) )

# Funkció a numbers_list négyzetre hurok használatával
def square_using_loop ( számok_lista ) :
négyzet_eredmény = [ ]
számára az egyiken ban ben numbers_list:
négyzet_eredmény. mellékel ( az egyiken** 2 )
Visszatérés négyzet_eredmény
# Funkció a páros számok_listájának ciklus segítségével történő szűrésére
def filter_even_using_loop ( számok_lista ) :
filter_result = [ ]
számára az egyiken ban ben numbers_list:
ha egy %-on 2 == 0 :
filter_result. mellékel ( az egyiken )
Visszatérés filter_result
# Funkció a numbers_list hurok segítségével történő rendezésére
def sort_using_loop ( számok_lista ) :
Visszatérés rendezve ( számok_lista )
# Mérje meg a négyzetszámok_listájához szükséges időt a map() segítségével
map_time = tt. Timei ( lambda : lista ( térkép ( lambda x: x ** 2 , számok_lista ) ) , szám = 1000 )
# Mérje meg a páros számok_lista szűrésének idejét a filter() segítségével
filter_time = tt. Timei ( lambda : lista ( szűrő ( lambda x: x % 2 == 0 , számok_lista ) ) , szám = 1000 )
# Mérje meg a numbers_list rendezéséhez szükséges időt a sorted() segítségével
rendezett_idő = tt. Timei ( lambda : rendezve ( számok_lista ) , szám = 1000 )
# Mérje meg a numbers_list négyzetbeállításának idejét hurok segítségével
loop_map_time = tt. Timei ( lambda : square_using_loop ( számok_lista ) , szám = 1000 )
# Mérje meg a páros számok_lista szűrésének idejét hurok segítségével
loop_filter_time = tt. Timei ( lambda : filter_even_using_loop ( számok_lista ) , szám = 1000 )
# Mérje meg a numbers_list rendezéséhez szükséges időt hurok segítségével
loop_sorted_time = tt. Timei ( lambda : sort_using_loop ( számok_lista ) , szám = 1000 )
nyomtatás ( 'A számlista 10000 elemet tartalmaz' )
nyomtatás ( f 'Map() idő: {map_time:.6f} másodperc' )
nyomtatás ( f 'Szűrő() idő: {filter_time:.6f} másodperc' )
nyomtatás ( f 'Rendezett() idő: {sorted_time:.6f} másodperc' )
nyomtatás ( f 'Hurok (térkép) ideje: {loop_map_time:.6f} másodperc' )
nyomtatás ( f 'Hurok (szűrő) idő: {loop_filter_time:.6f} másodperc' )
nyomtatás ( f 'Hurok (rendezési) idő: {loop_sorted_time:.6f} másodperc' )

Valószínűleg észre fogjuk venni, hogy a beépített függvények (map(), filter() és sorted()) gyorsabbak, mint az egyéni ciklusok ezekhez a gyakori feladatokhoz. A Python beépített funkciói tömörebb és érthetőbb megközelítést kínálnak ezeknek a feladatoknak a végrehajtásához, és rendkívül optimalizáltak a teljesítményre.

Optimalizálja a hurkokat

Ha szükséges a ciklusok írása, van néhány technika, amellyel felgyorsíthatjuk őket. Általában a range() ciklus gyorsabb, mint visszafelé. Ennek az az oka, hogy a range() a lista invertálása nélkül generál egy iterátort, ami hosszú listák esetén költséges művelet lehet. Ezenkívül, mivel a range() nem hoz létre új listát a memóriában, kevesebb memóriát használ.

OptimizeLoop.py:

import Timei mint tt
# A numbers_list mintalistája
számok_lista = lista ( hatótávolság ( 1 , 100 000 ) )
# Funkció, amellyel a listát fordított sorrendben ismételheti
def loop_reverse_iteration ( ) :
eredmény_fordított = [ ]
számára j ban ben hatótávolság ( csak ( számok_lista ) - 1 , - 1 , - 1 ) :
eredmény_fordított. mellékel ( számok_lista [ j ] )
Visszatérés eredmény_fordított
# Funkció a listán a range() segítségével
def loop_range_iteration ( ) :
eredmény_tartomány = [ ]
számára k ban ben hatótávolság ( csak ( számok_lista ) ) :
eredmény_tartomány. mellékel ( számok_lista [ k ] )
Visszatérés eredmény_tartomány
# Mérje meg a fordított iteráció végrehajtásához szükséges időt
fordított_idő = tt. Timei ( loop_reverse_iteration , szám = 1000 )
# Mérje meg a tartományiteráció végrehajtásához szükséges időt
range_time = tt. Timei ( loop_range_iteration , szám = 1000 )
nyomtatás ( 'A számlista 100 000 rekordot tartalmaz' )
nyomtatás ( f 'Fordított iterációs idő: {reverse_time:.6f} másodperc' )
nyomtatás ( f 'Tartomány iterációs ideje: {range_time:.6f} másodperc' )

Kerülje a szükségtelen funkcióhívásokat

Valahányszor egy függvényt meghívnak, van némi többletköltség. A kód gyorsabban fut, ha elkerüljük a szükségtelen függvényhívásokat. Például egy értéket kiszámító függvény ismételt végrehajtása helyett próbálja meg eltárolni a számítás eredményét egy változóban, és azt használni.

Eszközök a profilalkotáshoz

Ha többet szeretne megtudni a kód teljesítményéről, a beépített profilalkotáson kívül használhatjuk a külső profilozó csomagokat, például a cProfile, Pyflame vagy SnakeViz.

Gyorsítótár eredmények

Ha a kódunknak költséges számításokat kell végrehajtania, időmegtakarítás céljából fontolóra veheti az eredmények gyorsítótárazását.

Kód refaktorálás

A kód átalakítása, hogy könnyebben olvasható és karbantartható legyen, néha az optimalizálás szükséges része. Egy gyorsabb program tisztább is lehet.

A Just-in-Time összeállítás (JIT) használata

Az olyan könyvtárak, mint a PyPy vagy a Numba, JIT-összeállítást biztosíthatnak, amely jelentősen felgyorsíthatja bizonyos típusú Python-kódokat.

Frissítse a Pythont

Győződjön meg arról, hogy a Python legújabb verzióját használja, mivel az újabb verziók gyakran tartalmaznak teljesítményjavításokat.

Párhuzamosság és párhuzamosság

A párhuzamosítható folyamatok esetében vizsgálja meg a párhuzamos és szinkronizálási technikákat, mint például a többfeldolgozás, a szálfűzés vagy az aszinkronizálás.

Ne feledje, hogy a teljesítményértékelésnek és a profilalkotásnak kell az optimalizálás fő mozgatórugóinak lennie. Koncentráljon kódunk azon területeinek fejlesztésére, amelyek a legjelentősebb hatással vannak a teljesítményre, és folyamatosan tesztelje fejlesztéseit, hogy megbizonyosodjon arról, hogy a kívánt hatást érik el anélkül, hogy további hibákat okoznának.

Következtetés

Összefoglalva, a Python-kód optimalizálása kulcsfontosságú a jobb teljesítmény és az erőforrás-hatékonyság szempontjából. A fejlesztők nagymértékben növelhetik Python-alkalmazásaik végrehajtási sebességét és válaszkészségét különféle technikák segítségével, például a megfelelő adatstruktúrák kiválasztásával, a beépített funkciók kihasználásával, az extra hurkok csökkentésével és a memória hatékony kezelésével. A folyamatos benchmarkingnak és profilalkotásnak kell irányítania az optimalizálási erőfeszítéseket, biztosítva, hogy a kódfejlesztések megfeleljenek a valós teljesítmény követelményeinek. A projekt hosszú távú sikerének garantálása és az új problémák bevezetésének esélyének csökkentése érdekében a kód optimalizálását folyamatosan egyensúlyban kell tartani a kód olvashatóságának és karbantarthatóságának céljaival.