Paano I-optimize ang Iyong Mga Python Script para sa Mas Mahusay na Pagganap

Paano I Optimize Ang Iyong Mga Python Script Para Sa Mas Mahusay Na Pagganap



Ang pag-optimize ng mga script ng Python para sa mas mahusay na pagganap ay kinabibilangan ng pagtukoy at pagtugon sa mga bottleneck sa aming code, na ginagawa itong mas mabilis at mas mahusay. Ang Python ay isang sikat at makapangyarihang programming language na ginagamit sa maraming application sa kasalukuyan kabilang ang data analysis, ML projects (machine learning), web development, at marami pa. Ang pag-optimize ng code ng Python ay isang diskarte upang mapabuti ang bilis at kahusayan ng developer program kapag nagsasagawa ng anumang aktibidad gamit ang mas kaunting linya ng code, mas kaunting memorya, o karagdagang mapagkukunan. Ang malaki at hindi mahusay na code ay maaaring makapagpabagal sa programa na maaaring magresulta sa hindi magandang kasiyahan ng kliyente at potensyal na pagkawala ng pananalapi, o ang pangangailangan para sa higit pang trabaho upang ayusin at i-troubleshoot.

Ito ay kinakailangan habang gumagawa ng isang gawain na nangangailangan ng pagproseso ng ilang mga aksyon o data. Samakatuwid, ang paglipat at pagpapahusay ng ilang hindi epektibong mga bloke at pagpapagana ng code ay maaaring magkaroon ng mga kamangha-manghang resulta tulad ng sumusunod:

  1. Palakasin ang pagganap ng application
  2. Lumikha ng nababasa at organisadong code
  3. Gawing mas simple ang pagsubaybay at pag-debug ng error
  4. Mag-imbak ng malaking computational power at iba pa

I-profile ang Iyong Code

Bago tayo magsimulang mag-optimize, mahalagang tukuyin ang mga bahagi ng code ng proyekto na nagpapabagal dito. Ang mga diskarte para sa pag-profile sa Python ay kasama ang cProfile at mga pakete ng profile. Gamitin ang mga naturang tool upang masukat kung gaano kabilis ang pagpapatupad ng ilang function at linya ng code. Ang cProfile module ay gumagawa ng ulat na nagdedetalye kung gaano katagal tumakbo ang bawat script function. Ang ulat na ito ay maaaring makatulong sa amin na mahanap ang anumang mga function na tumatakbo nang mabagal upang mapagbuti namin ang mga ito.







Snippet ng Code:



angkat cProfile bilang cP
def kalkulahinSum ( inputNumber ) :
sum_of_input_numbers = 0
habang inputNumber > 0 :
sum_of_input_numbers + = inputNumber % 10
inputNumber // = 10
print ( 'Ang kabuuan ng Lahat ng Digit sa Input Number ay: 'sum_of_input_numbers'' )
bumalik sum_of_input_numbers
def main_func ( ) :
cP. tumakbo ( 'calculateSum(9876543789)' )
kung __pangalan__ == '__pangunahin__' :
main_func ( )

Ang programa ay gumagawa ng kabuuang limang function na tawag tulad ng nakikita sa unang linya ng output. Ang mga detalye ng bawat function call ay ipinapakita sa mga sumusunod na ilang linya kabilang ang bilang ng beses na ang function ay na-invoke, ang kabuuang tagal ng oras sa function, ang tagal ng oras sa bawat tawag, at ang kabuuang tagal ng oras sa function (kabilang ang lahat ng mga function na tinatawag nito).



Bukod pa rito, ang programa ay nagpi-print ng isang ulat sa prompt screen na nagpapakita na ang programa ay nakumpleto ang oras ng pagpapatupad ng lahat ng mga gawain nito sa loob ng 0.000 segundo. Ipinapakita nito kung gaano kabilis ang programa.





Piliin ang Tamang Istraktura ng Data

Ang mga katangian ng pagganap ay nakasalalay sa istraktura ng data. Sa partikular, ang mga diksyunaryo ay mas mabilis para sa mga paghahanap kaysa sa mga listahan tungkol sa pangkalahatang layunin na imbakan. Piliin ang istruktura ng data na pinakaangkop para sa mga pagpapatakbong isasagawa namin sa iyong data kung alam mo ang mga iyon. Ang sumusunod na halimbawa ay nag-iimbestiga sa pagiging epektibo ng iba't ibang istruktura ng data para sa magkaparehong proseso upang matukoy kung mayroong elemento sa istruktura ng data.



Sinusuri namin ang oras na kinakailangan upang suriin kung mayroong elemento sa bawat istraktura ng data—isang listahan, hanay, at diksyunaryo—at ihambing ang mga ito.

OptimizeDataType.py:

angkat Timei bilang tt
angkat random bilang rndobj
# Bumuo ng isang listahan ng mga integer
random_data_list = [ rndobj. walang kwenta ( 1 , 10000 ) para sa _ sa saklaw ( 10000 ) ]
# Lumikha ng isang set mula sa parehong data
random_data_set = itakda ( random_data_list )

# Lumikha ng diksyunaryo na may parehong data tulad ng mga susi
obj_DataDictionary = { sa isa: wala para sa sa isa sa random_data_list }

# Elemento na hahanapin (umiiral sa data)
random_number_to_find = rndobj. pagpili ( random_data_list )

# Sukatin ang oras upang suriin ang pagiging miyembro sa isang listahan
list_time = tt. Timei ( lambda : random_number_to_find sa random_data_list , numero = 1000 )

# Sukatin ang oras upang suriin ang membership sa isang set
set_time = tt. Timei ( lambda : random_number_to_find sa random_data_set , numero = 1000 )

# Sukatin ang oras upang suriin ang pagiging miyembro sa isang diksyunaryo
dict_time = tt. Timei ( lambda : random_number_to_find sa obj_DataDictionary , numero = 1000 )

print ( f 'Oras ng pagsusuri sa listahan ng membership: {list_time:.6f} na segundo' )
print ( f 'Itakda ang oras ng pagsusuri ng membership: {set_time:.6f} segundo' )
print ( f 'Oras ng pagsusuri ng membership sa diksyunaryo: {dict_time:.6f} segundo' )

Inihahambing ng code na ito ang pagganap ng mga listahan, set, at diksyunaryo kapag gumagawa ng mga pagsusuri sa membership. Sa pangkalahatan, mas mabilis ang mga set at diksyunaryo kaysa sa mga listahan para sa mga pagsubok sa membership dahil ginagamit nila ang mga paghahanap na batay sa hash, kaya mayroon silang average na pagiging kumplikado ng oras na O(1). Ang mga listahan, sa kabilang banda, ay dapat gumawa ng mga linear na paghahanap na nagreresulta sa mga pagsubok sa membership na may O(n) na pagiging kumplikado ng oras.

  Awtomatikong nabuo ang isang screen shot ng isang paglalarawan ng computer

Gamitin ang Mga Built-In na Function sa halip na Mga Loop

Maraming mga built-in na function o pamamaraan sa Python ang maaaring gamitin upang magsagawa ng mga tipikal na gawain tulad ng pag-filter, pag-uuri, at pagmamapa. Ang paggamit ng mga gawaing ito sa halip na gumawa ng mga loop ng isang tao ay nakakatulong na mapabilis ang code dahil ang mga ito ay madalas na na-optimize sa pagganap.

Bumuo tayo ng ilang sample code upang ihambing ang pagganap ng paglikha ng mga custom na loop sa pamamagitan ng paggamit ng mga built-in na function para sa mga karaniwang trabaho (gaya ng map(), filter(), at sorted()). Susuriin namin kung gaano kahusay gumanap ang iba't ibang paraan ng pagmamapa, pagsasala, at pag-uuri.

BuiltInFunctions.py:

angkat Timei bilang tt
# Halimbawang listahan ng mga numero_listahan
numbers_list = listahan ( saklaw ( 1 , 10000 ) )

# Function sa square numbers_list gamit ang loop
def square_using_loop ( numbers_list ) :
square_result = [ ]
para sa sa isa sa numbers_list:
square_result. dugtungan ( sa isa ** 2 )
bumalik square_result
# Function na i-filter ang even numbers_list gamit ang isang loop
def filter_even_using_loop ( numbers_list ) :
filter_result = [ ]
para sa sa isa sa numbers_list:
kung sa isa % 2 == 0 :
filter_result. dugtungan ( sa isa )
bumalik filter_result
# Function upang pagbukud-bukurin ang mga numero_lista gamit ang isang loop
def sort_using_loop ( numbers_list ) :
bumalik pinagsunod-sunod ( numbers_list )
# Sukatin ang oras upang parisukat ang mga numero_lista gamit ang mapa()
mapa_oras = tt. Timei ( lambda : listahan ( mapa ( lambda x: x ** 2 , numbers_list ) ) , numero = 1000 )
# Sukatin ang oras upang i-filter ang even numbers_list gamit ang filter()
filter_time = tt. Timei ( lambda : listahan ( salain ( lambda x: x % 2 == 0 , numbers_list ) ) , numero = 1000 )
# Sukatin ang oras upang pagbukud-bukurin ang mga numero_listahan gamit ang sorted()
sorted_time = tt. Timei ( lambda : pinagsunod-sunod ( numbers_list ) , numero = 1000 )
# Sukatin ang oras sa mga numero_list gamit ang isang loop
loop_map_time = tt. Timei ( lambda : square_using_loop ( numbers_list ) , numero = 1000 )
# Sukatin ang oras upang i-filter ang even numbers_list gamit ang isang loop
loop_filter_time = tt. Timei ( lambda : filter_even_using_loop ( numbers_list ) , numero = 1000 )
# Sukatin ang oras upang pagbukud-bukurin ang mga numero_lista gamit ang isang loop
loop_sorted_time = tt. Timei ( lambda : sort_using_loop ( numbers_list ) , numero = 1000 )
print ( 'Ang Listahan ng Numero ay naglalaman ng 10000 elemento' )
print ( f 'Map() Time: {map_time:.6f} seconds' )
print ( f 'Filter() Time: {filter_time:.6f} seconds' )
print ( f 'Orasted() Time: {sorted_time:.6f} seconds' )
print ( f 'Oras ng Loop (Map): {loop_map_time:.6f} segundo' )
print ( f 'Oras ng Loop (Filter): {loop_filter_time:.6f} segundo' )
print ( f 'Loop (Sorted) Time: {loop_sorted_time:.6f} seconds' )

Malamang na mapapansin natin na ang mga built-in na function (map(), filter(), at sorted()) ay mas mabilis kaysa sa custom na mga loop para sa mga karaniwang gawaing ito. Ang mga built-in na function sa Python ay nag-aalok ng mas maigsi at nauunawaan na diskarte upang maisagawa ang mga gawaing ito at lubos na na-optimize para sa pagganap.

I-optimize ang Loops

Kung ang pagsusulat ng mga loop ay kinakailangan, may ilang mga diskarte na maaari naming gawin upang mapabilis ang mga ito. Sa pangkalahatan, ang range() loop ay mas mabilis kaysa sa pag-ulit pabalik. Ito ay dahil ang range() ay bumubuo ng isang iterator nang hindi binabaligtad ang listahan na maaaring maging isang magastos na operasyon para sa mahahabang listahan. Bilang karagdagan, dahil ang range() ay hindi bumubuo ng isang bagong listahan sa memorya, gumagamit ito ng mas kaunting memorya.

OptimizeLoop.py:

angkat Timei bilang tt
# Halimbawang listahan ng mga numero_listahan
numbers_list = listahan ( saklaw ( 1 , 100000 ) )
# Function na umulit sa listahan sa reverse order
def loop_reverse_iteration ( ) :
resulta_baligtad = [ ]
para sa j sa saklaw ( lamang ( numbers_list ) - 1 , - 1 , - 1 ) :
resulta_baligtad. dugtungan ( numbers_list [ j ] )
bumalik resulta_baligtad
# Function na umulit sa listahan gamit ang range()
def loop_range_iteration ( ) :
resulta_range = [ ]
para sa k sa saklaw ( lamang ( numbers_list ) ) :
resulta_range. dugtungan ( numbers_list [ k ] )
bumalik resulta_range
# Sukatin ang oras na kinakailangan upang maisagawa ang reverse iteration
reverse_time = tt. Timei ( loop_reverse_iteration , numero = 1000 )
# Sukatin ang oras na kinakailangan upang maisagawa ang pag-ulit ng saklaw
saklaw_oras = tt. Timei ( loop_range_iteration , numero = 1000 )
print ( 'Ang listahan ng numero ay naglalaman ng 100000 na talaan' )
print ( f 'Reverse Iteration Time: {reverse_time:.6f} seconds' )
print ( f 'Range Iteration Time: {range_time:.6f} seconds' )

Iwasan ang Mga Hindi Kailangang Function Call

Mayroong ilang overhead sa tuwing tinatawag ang isang function. Ang code ay tumatakbo nang mas mabilis kung ang mga hindi kinakailangang function na tawag ay maiiwasan. Halimbawa, sa halip na paulit-ulit na magsagawa ng isang function na nagkalkula ng isang halaga, subukang iimbak ang resulta ng pagkalkula sa isang variable at gamitin ito.

Mga tool para sa Profiling

Upang matuto nang higit pa tungkol sa pagganap ng iyong code, bilang karagdagan sa built-in na pag-profile, maaari naming gamitin ang mga panlabas na profile ng package tulad ng cProfile, Pyflame, o SnakeViz.

Mga Resulta ng Cache

Kung ang aming code ay kailangang magsagawa ng mga mamahaling kalkulasyon, maaari naming isaalang-alang ang pag-cache ng mga resulta upang makatipid ng oras.

Code Refactoring

Ang pag-refactor sa code upang gawing mas madaling basahin at mapanatili ay kung minsan ay isang kinakailangang bahagi ng pag-optimize nito. Ang isang mas mabilis na programa ay maaari ding maging mas malinis.

Gamitin ang Just-in-Time Compilation (JIT)

Ang mga aklatan tulad ng PyPy o Numba ay maaaring magbigay ng JIT compilation na maaaring makabuluhang mapabilis ang ilang uri ng Python code.

I-upgrade ang Python

Tiyaking ginagamit mo ang pinakabagong bersyon ng Python dahil madalas na kasama sa mga mas bagong bersyon ang mga pagpapahusay sa pagganap.

Parallelism at Concurrency

Para sa mga prosesong maaaring i-parallelize, siyasatin ang parallel at synchronization techniques tulad ng multiprocessing, threading, o asyncio.

Tandaan na ang pag-benchmark at pag-profile ay dapat na pangunahing mga driver ng pag-optimize. Tumutok sa pagpapabuti ng mga bahagi ng aming code na may pinakamahalagang epekto sa pagganap, at patuloy na subukan ang iyong mga pagpapabuti upang matiyak na mayroon ang mga ito ng ninanais na mga epekto nang hindi nagpapakilala ng higit pang mga depekto.

Konklusyon

Sa konklusyon, ang Python code optimization ay mahalaga para sa pinahusay na pagganap at pagiging epektibo ng mapagkukunan. Maaaring lubos na mapataas ng mga developer ang bilis ng pagpapatupad at pagtugon ng kanilang mga Python application gamit ang iba't ibang mga diskarte tulad ng pagpili ng naaangkop na mga istruktura ng data, paggamit ng mga built-in na function, pagbabawas ng mga karagdagang loop, at epektibong pamamahala sa memorya. Ang patuloy na pag-benchmark at pag-profile ay dapat na magdirekta sa mga pagsusumikap sa pag-optimize, na tinitiyak na ang mga pagsulong ng code ay tumutugma sa mga kinakailangan sa pagganap sa totoong mundo. Upang magarantiya ang isang pangmatagalang tagumpay ng proyekto at mapababa ang pagkakataong magpasok ng mga bagong problema, ang pag-optimize ng code ay dapat na palaging balanse sa mga layunin ng pagiging madaling mabasa at mapanatili ng code.