Jak optimalizovat své Python skripty pro lepší výkon

Jak Optimalizovat Sve Python Skripty Pro Lepsi Vykon



Optimalizace skriptů Python pro lepší výkon zahrnuje identifikaci a řešení úzkých míst v našem kódu, díky čemuž běží rychleji a efektivněji. Python je populární a výkonný programovací jazyk, který se v současnosti používá v mnoha aplikacích včetně analýzy dat, projektů ML (strojové učení), vývoje webu a mnoha dalších. Optimalizace kódu Python je strategie ke zlepšení rychlosti a efektivity vývojářského programu při provádění jakékoli činnosti s použitím menšího počtu řádků kódu, menší paměti nebo dodatečných zdrojů. Velký a neefektivní kód může zpomalit program, což může mít za následek špatnou spokojenost klienta a potenciální finanční ztrátu nebo potřebu více práce na opravě a odstraňování problémů.

Je to nutné při provádění úkolu, který vyžaduje zpracování několika akcí nebo dat. Vypnutí a vylepšení některých neefektivních bloků kódu a funkcí proto může mít úžasné výsledky, jako jsou následující:

  1. Zvyšte výkon aplikace
  2. Vytvořte čitelný a organizovaný kód
  3. Usnadněte sledování chyb a ladění
  4. Ušetřete značný výpočetní výkon a tak dále

Profilujte svůj kód

Než začneme s optimalizací, je nezbytné identifikovat části kódu projektu, které jej zpomalují. Techniky profilování v Pythonu zahrnují balíčky cProfile a profile. Pomocí těchto nástrojů změřte, jak rychle se určité funkce a řádky kódu provádějí. Modul cProfile vytváří zprávu, která podrobně popisuje, jak dlouho trvá spuštění každé funkce skriptu. Tato zpráva nám může pomoci najít všechny funkce, které běží pomalu, abychom je mohli vylepšit.







Úryvek kódu:



import cProfile tak jako cP
def vypočítat Součet ( inputNumber ) :
součet_vstupních_čísl = 0
zatímco inputNumber > 0 :
součet_vstupních_čísl + = inputNumber % 10
inputNumber // = 10
tisk ( 'Součet všech číslic ve vstupním čísle je: 'součet_vstupních_čísel'' )
vrátit se součet_vstupních_čísl
def main_func ( ) :
cP. běh ( 'calculateSum(9876543789)' )
-li __název__ == '__hlavní__' :
main_func ( )

Program provede celkem pět volání funkcí, jak je vidět na prvním řádku výstupu. Podrobnosti o každém volání funkce jsou zobrazeny na následujících několika řádcích včetně počtu, kolikrát byla funkce vyvolána, celkové doby trvání funkce, doby trvání na volání a celkového množství času ve funkci (včetně všechny funkce, které se nazývá).



Kromě toho program vytiskne zprávu na obrazovce s výzvou, která ukazuje, že program dokončí dobu provádění všech svých úkolů do 0,000 sekund. To ukazuje, jak rychlý je program.





Vyberte správnou datovou strukturu

Výkonové charakteristiky jsou závislé na datové struktuře. Zejména slovníky jsou rychlejší pro vyhledávání než seznamy týkající se univerzálního úložiště. Vyberte datovou strukturu, která je nejvhodnější pro operace, které budeme s vašimi daty provádět, pokud je znáte. Následující příklad zkoumá efektivitu různých datových struktur pro identický proces za účelem zjištění, zda je prvek v datové struktuře přítomen.



Vyhodnocujeme čas potřebný ke kontrole, zda je prvek přítomen v každé datové struktuře – seznamu, sadě a slovníku – a porovnáváme je.

OptimizeDataType.py:

import Timei tak jako tt
import náhodný tak jako rndobj
# Vygenerujte seznam celých čísel
seznam náhodných_dat = [ rndobj. randint ( 1 , 10 000 ) pro _ v rozsah ( 10 000 ) ]
# Vytvořte sadu ze stejných dat
random_data_set = soubor ( seznam náhodných_dat )

# Vytvořte slovník se stejnými daty jako klíče
obj_DataDictionary = { na jednom: Žádný pro na jednom v seznam náhodných_dat }

# Prvek k vyhledání (existuje v datech)
náhodné_číslo_k_hledání = rndobj. výběr ( seznam náhodných_dat )

# Změřte čas pro kontrolu členství v seznamu
seznam_čas = tt. Timei ( lambda : náhodné_číslo_k_hledání v seznam náhodných_dat , číslo = 1000 )

# Změřte čas pro kontrolu členství v sadě
set_time = tt. Timei ( lambda : náhodné_číslo_k_hledání v random_data_set , číslo = 1000 )

# Změřte čas pro kontrolu členství ve slovníku
dict_time = tt. Timei ( lambda : náhodné_číslo_k_hledání v obj_DataDictionary , číslo = 1000 )

tisk ( F 'Čas kontroly členství v seznamu: {list_time:.6f} sekund' )
tisk ( F 'Nastavit čas kontroly členství: {set_time:.6f} sekund' )
tisk ( F 'Čas kontroly členství ve slovníku: {dict_time:.6f} sekund' )

Tento kód porovnává výkon seznamů, sad a slovníků při provádění kontrol členství. Obecně jsou množiny a slovníky podstatně rychlejší než seznamy pro testy členství, protože používají vyhledávání na bázi hash, takže mají průměrnou časovou složitost O(1). Seznamy na druhé straně musí provádět lineární vyhledávání, což vede k testům členství s časovou složitostí O(n).

  Automaticky vygenerovaný snímek obrazovky s popisem počítače

Místo smyček použijte vestavěné funkce

Četné vestavěné funkce nebo metody v Pythonu lze použít k provádění typických úkolů, jako je filtrování, třídění a mapování. Použití těchto rutin namísto vytváření vlastních smyček pomáhá urychlit kód, protože jsou často optimalizovány pro výkon.

Pojďme sestavit nějaký ukázkový kód pro porovnání výkonu vytváření vlastních smyček s využitím vestavěných funkcí pro typické úlohy (jako je map(), filter() a sort()). Vyhodnotíme, jak dobře fungují různé metody mapování, filtrace a třídění.

BuiltInFunctions.py:

import Timei tak jako tt
# Ukázkový seznam čísel_seznamu
číselný_seznam = seznam ( rozsah ( 1 , 10 000 ) )

# Funkce na čtverec čísel_seznamu pomocí smyčky
def square_using_loop ( číselný_seznam ) :
čtvercový_výsledek = [ ]
pro na jednom v číselný_seznam:
čtvercový_výsledek. připojit ( na jednom ** 2 )
vrátit se čtvercový_výsledek
# Funkce pro filtrování seznamu sudých čísel pomocí smyčky
def filter_even_using_loop ( číselný_seznam ) :
výsledek_filtru = [ ]
pro na jednom v číselný_seznam:
-li na jednom % 2 == 0 :
výsledek_filtru. připojit ( na jednom )
vrátit se výsledek_filtru
# Funkce pro třídění seznamu čísel pomocí smyčky
def sort_using_loop ( číselný_seznam ) :
vrátit se seřazeno ( číselný_seznam )
# Změřte čas do čtverce čísel_seznamu pomocí map()
map_time = tt. Timei ( lambda : seznam ( mapa ( lambda x: x ** 2 , číselný_seznam ) ) , číslo = 1000 )
# Změřte čas pro filtrování seznamu sudých čísel pomocí filter()
filtr_čas = tt. Timei ( lambda : seznam ( filtr ( lambda x: x % 2 == 0 , číselný_seznam ) ) , číslo = 1000 )
# Změřte čas na seřazení seznamu čísel pomocí sort()
seřazený_čas = tt. Timei ( lambda : seřazeno ( číselný_seznam ) , číslo = 1000 )
# Změřte čas do čtverce čísel_seznamu pomocí smyčky
loop_map_time = tt. Timei ( lambda : square_using_loop ( číselný_seznam ) , číslo = 1000 )
# Změřte čas pro filtrování seznamu sudých čísel pomocí smyčky
loop_filter_time = tt. Timei ( lambda : filter_even_using_loop ( číselný_seznam ) , číslo = 1000 )
# Změřte čas pro třídění seznamu čísel pomocí smyčky
loop_sorted_time = tt. Timei ( lambda : sort_using_loop ( číselný_seznam ) , číslo = 1000 )
tisk ( 'Seznam čísel obsahuje 10 000 prvků' )
tisk ( F 'Map() Time: {map_time:.6f} sekund' )
tisk ( F 'Filter() Time: {filter_time:.6f} sekund' )
tisk ( F 'Sorted() Time: {sorted_time:.6f} sekund' )
tisk ( F 'Čas smyčky (mapy): {loop_map_time:.6f} sekund' )
tisk ( F 'Čas smyčky (filtru): {loop_filter_time:.6f} sekund' )
tisk ( F 'Čas smyčky (tříděno): {loop_sorted_time:.6f} sekund' )

Pravděpodobně zjistíme, že vestavěné funkce (map(), filter() a sort()) jsou rychlejší než vlastní smyčky pro tyto běžné úkoly. Vestavěné funkce v Pythonu nabízejí stručnější a srozumitelnější přístup k provádění těchto úkolů a jsou vysoce optimalizované pro výkon.

Optimalizujte smyčky

Pokud je psaní smyček nezbytné, existuje několik technik, které můžeme udělat, abychom je urychlili. Obecně je cyklus range() rychlejší než iterace zpět. Je to proto, že range() generuje iterátor bez invertování seznamu, což může být nákladná operace pro dlouhé seznamy. Navíc, protože range() nevytváří nový seznam v paměti, využívá méně paměti.

OptimizeLoop.py:

import Timei tak jako tt
# Ukázkový seznam čísel_seznamu
číselný_seznam = seznam ( rozsah ( 1 , 100 000 ) )
# Funkce pro iteraci seznamu v opačném pořadí
def loop_reverse_itration ( ) :
result_reverse = [ ]
pro j v rozsah ( jen ( číselný_seznam ) - 1 , - 1 , - 1 ) :
result_reverse. připojit ( číselný_seznam [ j ] )
vrátit se result_reverse
# Funkce pro iteraci seznamu pomocí range()
def opakování rozsahu_cyklu ( ) :
rozsah_výsledků = [ ]
pro k v rozsah ( jen ( číselný_seznam ) ) :
rozsah_výsledků. připojit ( číselný_seznam [ k ] )
vrátit se rozsah_výsledků
# Změřte čas potřebný k provedení obrácené iterace
reverzní_čas = tt. Timei ( loop_reverse_itration , číslo = 1000 )
# Změřte čas potřebný k provedení iterace rozsahu
rozsah_čas = tt. Timei ( opakování rozsahu_cyklu , číslo = 1000 )
tisk ( 'Seznam čísel obsahuje 100 000 záznamů' )
tisk ( F 'Čas zpětné iterace: {reverse_time:.6f} sekund' )
tisk ( F 'Doba iterace rozsahu: {range_time:.6f} sekund' )

Vyhněte se zbytečným voláním funkcí

Při každém volání funkce je určitá režie. Kód běží rychleji, pokud se vyhnete zbytečným voláním funkcí. Například místo opakovaného spouštění funkce, která vypočítá hodnotu, zkuste výsledek výpočtu uložit do proměnné a použít ji.

Nástroje pro profilování

Chcete-li se dozvědět více o výkonu vašeho kódu, můžeme kromě vestavěného profilování využít externí profilovací balíčky jako cProfile, Pyflame nebo SnakeViz.

Výsledky mezipaměti

Pokud náš kód potřebuje provádět nákladné výpočty, můžeme zvážit uložení výsledků do mezipaměti, abychom ušetřili čas.

Refaktorování kódu

Refaktorování kódu, aby se dal snadněji číst a udržovat, je někdy nezbytnou součástí jeho optimalizace. Rychlejší program může být také čistší.

Použijte kompilaci Just-in-Time (JIT)

Knihovny jako PyPy nebo Numba mohou poskytnout kompilaci JIT, která může výrazně urychlit určité typy kódu Python.

Upgradujte Python

Ujistěte se, že používáte nejnovější verzi Pythonu, protože novější verze často obsahují vylepšení výkonu.

Paralelismus a souběžnost

U procesů, které lze paralelizovat, prozkoumejte paralelní a synchronizační techniky, jako je multiprocessing, threading nebo asyncio.

Pamatujte, že benchmarking a profilování by měly být hlavními hybateli optimalizace. Soustřeďte se na vylepšování oblastí našeho kódu, které mají nejvýraznější vliv na výkon, a neustále svá vylepšení testujte, abyste se ujistili, že mají požadované účinky, aniž by přinášely další defekty.

Závěr

Závěrem lze říci, že optimalizace kódu Pythonu je zásadní pro lepší výkon a efektivitu zdrojů. Vývojáři mohou výrazně zvýšit rychlost spouštění a odezvu svých aplikací Python pomocí různých technik, jako je výběr vhodných datových struktur, využití vestavěných funkcí, snížení nadbytečných smyček a efektivní správa paměti. Neustálé srovnávání a profilování by mělo řídit úsilí o optimalizaci a zajistit, aby vylepšení kódu odpovídala požadavkům na výkon v reálném světě. Aby byl zaručen dlouhodobý úspěch projektu a snížila se pravděpodobnost zavedení nových problémů, optimalizace kódu by měla být neustále v rovnováze s cíli čitelnosti a udržovatelnosti kódu.