Jak używać cProfile do profilowania kodu Pythona

Python może nie jest najszybszym językiem, ale często jest wystarczająco szybki. A Python jest idealny, gdy czas programisty ma większe znaczenie niż czas procesora.

To powiedziawszy, jeśli dana aplikacja Pythona jest opóźniona, nie jesteś zobowiązany do jej wysysania. Narzędzia dołączone do standardowej instalacji interpretera języka Python mogą dostarczyć szczegółowych informacji zwrotnych na temat tego, które części programu są wolne, oraz podpowiedzieć, jak je przyspieszyć.

Jak korzystać z cProfile

cProfileModuł gromadzi statystyki dotyczące czasu realizacji programu Pythona. Może raportować wszystko, od całej aplikacji po pojedyncze oświadczenie lub wyrażenie.

Oto przykład zabawki, jak używać cProfile:

def add (x, y): x + = str (y) return x def add_2 (x, y): if y% 20000 == 0: z = [] for q in range (0,400000): z.append ( q) def main (): a = [] for n in range (0,200000): add (a, n) add_2 (a, n) if __name__ == '__main__': import cProfile cProfile.run ('main ( ) ') 

Ten przykład uruchamia funkcję aplikacji main()i analizuje wydajność main()i wszystko, co main()wywołuje. Możliwe jest również przeanalizowanie tylko  części programu, ale najczęściej używanym na początku jest profilowanie całego programu.

Uruchom powyższy przykład, a zostaniesz powitany czymś podobnym do następującego wyniku:

To, co jest tutaj pokazane, to lista wszystkich wywołań funkcji wykonywanych przez program, wraz ze statystykami dotyczącymi każdego z nich:

  • U góry (pierwsza linia na niebiesko) widzimy całkowitą liczbę wywołań wykonanych w profilowanym programie oraz całkowity czas wykonania. Możesz również zobaczyć figurę dla „wywołań pierwotnych”, oznaczających wywołania nierekurencyjne lub wywołania bezpośrednio do funkcji, która z kolei nie wywołuje siebie dalej na stosie wywołań.
  • ncalls : liczba wykonanych połączeń. Jeśli widzisz dwie liczby oddzielone ukośnikiem, druga liczba to liczba pierwotnych wywołań tej funkcji.
  • tottime : Całkowity czas spędzony w funkcji, bez wywołań innych funkcji.
  • percall : średni czas na połączenie dla tottime , obliczony na podstawie wzięcia tottime i podzielenia go przez ncall .
  • cumtime : Całkowity czas spędzony w funkcji, w tym wywołania innych funkcji.
  • percall (# 2): średni czas na połączenie dla cumtime ( suma czasu podzielona przez ncall ).
  • filename: lineno : nazwa pliku, numer linii i nazwa funkcji dla danego wywołania.

Jak modyfikować raporty cProfile

Domyślnie cProfilesortuje dane wyjściowe według „nazwy standardowej”, co oznacza, że ​​sortuje według tekstu z prawej kolumny (nazwa pliku, numer wiersza itp.).

Format domyślny jest przydatny, jeśli chcesz uzyskać ogólny, odgórny raport każdego wywołania funkcji w celach informacyjnych. Ale jeśli próbujesz dotrzeć do sedna wąskiego gardła, prawdopodobnie będziesz potrzebować najbardziej czasochłonnych części programu wymienionych jako pierwsze.

Możemy uzyskać te wyniki, wywołując  cProfile trochę inaczej. Zwróć uwagę, jak można przerobić dolną część powyższego programu, aby posortować statystyki według innej kolumny (w tym przypadku ncalls):

if __name__ == '__main__': import cProfile, pstats profiler = cProfile.Profile () profiler.enable () main () profiler.disable () stats = pstats.Stats (profiler) .sort_stats ('ncalls') stats.print_stats () 

Wyniki będą wyglądać mniej więcej tak:

Oto jak to wszystko działa:

  • Zamiast wykonywania polecenia drodze cProfile.run(), co nie jest bardzo elastyczny, tworzymy profilowania obiekt , profiler.
  • Kiedy chcemy sprofilować jakąś akcję, najpierw wywołujemy .enable()instancję obiektu profilera, następnie uruchamiamy akcję, a następnie wywołujemy .disable(). (Jest to jeden ze sposobów profilowania tylko części programu).
  • pstatsModuł jest wykorzystywany do manipulowania wyniki zebrane przez obiekt profilera i wydrukować te wyniki.

Połączenie obiektu profilera i pstatspozwala nam manipulować przechwyconymi danymi profilu - na przykład inaczej sortować wygenerowane statystyki. W tym przykładzie użycie .sort_stats('ncalls')posortuje statystyki według ncallskolumny. Dostępne są inne opcje sortowania.

Jak używać wyników cProfile do optymalizacji

Opcje sortowania dostępne dla cProfile wyników pozwalają nam wydobyć potencjalne wąskie gardła wydajności w programie.

ncalls

Pierwszą i najważniejszą informacją, jaką możesz odkryć, cProfilejest to, które funkcje są wywoływane najczęściej, za pośrednictwem ncallskolumny.

W Pythonie samo wykonanie wywołania funkcji wiąże się ze stosunkowo dużym narzutem. Jeśli jakaś funkcja jest wywoływana wielokrotnie w ścisłej pętli, nawet jeśli nie jest to funkcja długotrwała, ma to wpływ na wydajność.

W powyższym przykładzie funkcja add(i funkcja add_2) jest wywoływana wielokrotnie w pętli. Przeniesienie pętli do addsamej funkcji lub addcałkowite wbudowanie funkcji rozwiązałoby ten problem.

tottime

Kolejne przydatne dane statystyczne, na których wykonywanie program spędza większość czasu, za pośrednictwem tottimekolumny.

W powyższym przykładzie add_2funkcja używa pętli do symulacji niektórych kosztownych obliczeń, co przesuwa jej tottimewynik na szczyt. Każda funkcja z wysokim tottimewynikiem zasługuje na dokładne przyjrzenie się, zwłaszcza jeśli jest wywoływana wielokrotnie lub w ciasnej pętli.

Pamiętaj, że zawsze musisz wziąć pod uwagę kontekst,  w którym funkcja jest używana. Jeśli funkcja ma wysoką wartość, tottimeale jest wywoływana tylko raz - na przykład tylko podczas uruchamiania programu - jest mniej prawdopodobne, że będzie wąskim gardłem. Jeśli jednak próbujesz skrócić czas uruchamiania, będziesz chciał wiedzieć, czy funkcja wywoływana podczas uruchamiania sprawia, że ​​wszystko inne czeka.

Jak wyeksportować dane cProfile

Jeśli chcesz wykorzystać cProfilewygenerowane statystyki w bardziej zaawansowany sposób, możesz wyeksportować je do pliku danych:

stats = pstats.Stats (profiler) stats.dump_stats ('/ path / to / stats_file.dat') 

Ten plik można ponownie wczytać za pomocą pstatsmodułu, a następnie posortować lub wyświetlić za pomocą pstats. Dane mogą być również ponownie wykorzystywane przez inne programy. Dwa przykłady:

  • pyprof2calltreerenderuje szczegółowe wizualizacje wykresu połączeń programu i statystyk użytkowania na podstawie danych profilu. Ten artykuł zawiera szczegółowy przykład jego użycia w świecie rzeczywistym.
  • snakevizgeneruje również wizualizacje na podstawie cProfiledanych, ale używa innej reprezentacji danych - „rozbłysku słonecznego” zamiast wykresu „płomienia” pyprof2calltree.

Więcej niż cProfile do profilowania w Pythonie

cProfilenie jest jedynym sposobem na profilowanie aplikacji w Pythonie. cProfilejest z pewnością jednym z najwygodniejszych sposobów, biorąc pod uwagę, że jest dołączony do Pythona. Ale inni zasługują na uwagę.

Jeden projekt py-spybuduje profil dla aplikacji w języku Python przez próbkowanie jej wywołań. py-spymoże służyć do sprawdzania działającej aplikacji w języku Python bez konieczności jej zatrzymywania i ponownego uruchamiania oraz bez konieczności zmiany jej bazy kodu, dzięki czemu można jej używać do profilowania wdrożonych aplikacji. py-spygeneruje również pewne statystyki dotyczące narzutu ponoszonego przez środowisko wykonawcze Pythona (na przykład obciążenie związane ze zbieraniem elementów bezużytecznych), co cProfilenie.