Szukaj…


Uwagi

Próbując poprawić wydajność skryptu Python, przede wszystkim powinieneś być w stanie znaleźć wąskie gardło skryptu i zauważyć, że żadna optymalizacja nie może zrekompensować złego wyboru struktur danych lub błędów w projekcie algorytmu. Identyfikowanie wąskich gardeł wydajności można wykonać, profilując skrypt. Po drugie, nie próbuj zbyt wcześnie optymalizować procesu kodowania kosztem czytelności / projektu / jakości. Donald Knuth wypowiedział się na temat optymalizacji:

„Powinniśmy zapomnieć o małej wydajności, powiedzmy około 97% czasu: przedwczesna optymalizacja jest źródłem wszelkiego zła. Nie powinniśmy jednak tracić naszych szans w tak krytycznych 3%. ”

Profilowanie kodu

Przede wszystkim powinieneś być w stanie znaleźć wąskie gardło skryptu i zauważyć, że żadna optymalizacja nie zrekompensuje złego wyboru w strukturze danych lub błędów w projekcie algorytmu. Po drugie, nie próbuj zbyt wcześnie optymalizować procesu kodowania kosztem czytelności / projektu / jakości. Donald Knuth wypowiedział się na temat optymalizacji:

„Powinniśmy zapomnieć o niewielkiej wydajności, powiedzmy w około 97% przypadków: przedwczesna optymalizacja jest źródłem wszelkiego zła. Jednak nie powinniśmy tracić naszych możliwości w tak krytycznych 3%”

Do profilowania kodu masz kilka narzędzi: cProfile (lub wolniejszy profile ) ze standardowej biblioteki, line_profiler i timeit . Każdy z nich służy innym celom.

cProfile to profil deterministyczny: wywołanie funkcji, powrót funkcji i zdarzenia wyjątku są monitorowane, a przedziały między tymi zdarzeniami są precyzyjnie regulowane (do 0,001 s). Dokumentacja biblioteki ([ https://docs.python.org/2/library/profile.html][1]) zapewnia nam prosty przypadek użycia

import cProfile
def f(x):
    return "42!"
cProfile.run('f(12)')

Lub jeśli wolisz owinąć części istniejącego kodu:

import cProfile, pstats, StringIO
pr = cProfile.Profile()
pr.enable()
# ... do something ...
# ... long ...
pr.disable()
sortby = 'cumulative'
ps = pstats.Stats(pr, stream=s).sort_stats(sortby)
ps.print_stats()
print s.getvalue()

Spowoduje to utworzenie wyników wyglądających jak w poniższej tabeli, gdzie możesz szybko zobaczyć, gdzie Twój program spędza większość czasu i zidentyfikować funkcje do optymalizacji.

         3 function calls in 0.000 seconds

Ordered by: standard name
ncalls  tottime  percall  cumtime  percall filename:lineno(function)
     1    0.000    0.000    0.000    0.000 <stdin>:1(f)
     1    0.000    0.000    0.000    0.000 <string>:1(<module>)
     1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}

Moduł line_profiler ([ https://github.com/rkern/line_profiler][1]) jest przydatny do analizy kodu po linii. Nie jest to oczywiście możliwe do opanowania w przypadku długich skryptów, ale ma na celu urywki. Więcej informacji znajduje się w dokumentacji. Najłatwiejszym sposobem na rozpoczęcie jest użycie skryptu kernprof, jak wyjaśniono na stronie pakietu, pamiętaj, że musisz ręcznie określić funkcję (funkcje) do profilowania.

$ kernprof -l script_to_profile.py

kernprof utworzy instancję LineProfiler i wstawi ją do przestrzeni nazw __builtins__ z profilem nazw. Został napisany jako dekorator, więc w skrypcie dekorujesz funkcje, które chcesz profilować za pomocą @profile .

@profile
def slow_function(a, b, c):
    ...

Domyślne zachowanie kernprof polega na umieszczeniu wyników w pliku binarnym script_to_profile.py.lprof . Możesz powiedzieć kernprof, aby natychmiast wyświetlał sformatowane wyniki na terminalu za pomocą opcji [-v / - view]. W przeciwnym razie możesz wyświetlić wyniki później w następujący sposób:

$ python -m line_profiler script_to_profile.py.lprof

Wreszcie timeit zapewnia prosty sposób przetestowania jednego timeit lub małego wyrażenia zarówno z wiersza poleceń, jak i powłoki pytona. Ten moduł odpowie na pytanie, na przykład, czy szybciej jest zrozumieć listę lub użyć wbudowanej list() podczas przekształcania zestawu w listę. Spójrz na setup słowa kluczowego lub -s opcji, aby dodać kod instalacyjny.

>>> import timeit
>>> timeit.timeit('"-".join(str(n) for n in range(100))', number=10000)
0.8187260627746582

z terminala

$ python -m timeit '"-".join(str(n) for n in range(100))'
10000 loops, best of 3: 40.3 usec per loop


Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow