Ako môžete profilovať skript Python?

Projekt Euler a iné kódovacie súťaže majú často stanovený maximálny čas behu alebo sa ľudia chvália, ako rýchlo beží ich konkrétne riešenie. V prípade jazyka python sú niekedy prístupy trochu kľukaté - t. j. pridávanie časového kódu do __main__.

Aký je dobrý spôsob, ako profilovať, ako dlho trvá spustenie programu v jazyku Python?

Riešenie

Python obsahuje profilovač s názvom cProfile. Uvádza nielen celkový čas behu, ale aj časy každej funkcie zvlášť a informuje vás, koľkokrát bola každá funkcia volaná, čo uľahčuje určenie, kde by ste mali vykonať optimalizáciu.

Môžete ho zavolať z vášho kódu alebo z interpretu, napríklad takto:

import cProfile
cProfile.run('foo()')

Ešte užitočnejšie je, že cProfile môžete vyvolať pri spustení skriptu:

python -m cProfile myscript.py

Aby to bolo ešte jednoduchšie, vytvoril som malý dávkový súbor s názvom 'profile.bat':

python -m cProfile %1

Takže všetko, čo musím urobiť, je spustiť:

profile euler048.py

A dostanem toto:

Jazyk: lang-none -->

1007 function calls in 0.061 CPU seconds

Ordered by: standard name
ncalls  tottime  percall  cumtime  percall filename:lineno(function)
    1    0.000    0.000    0.061    0.061 :1()
 1000    0.051    0.000    0.051    0.000 euler048.py:2()
    1    0.005    0.005    0.061    0.061 euler048.py:2()
    1    0.000    0.000    0.061    0.061 {execfile}
    1    0.002    0.002    0.053    0.053 {map}
    1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler objects}
    1    0.000    0.000    0.000    0.000 {range}
    1    0.003    0.003    0.003    0.003 {sum}

EDIT: Aktualizovaný odkaz na dobrý video zdroj z PyCon 2013 s názvom Python Profiling [Tiež cez YouTube](https://www.youtube.com/watch?v=QJwVYlDzAXs).

Komentáre (13)

Stojí za to upozorniť, že použitie profilera funguje (v predvolenom nastavení) len na hlavnom vlákne a v prípade použitia iných vlákien nezískate žiadne informácie. To môže byť trochu chyták, pretože v dokumentácii k profilovaču sa o tom vôbec nehovorí.

Ak chcete profilovať aj vlákna, budete'sa chcieť pozrieť na funkciu threading.setprofile() v dokumentácii.

Môžete si na to vytvoriť aj vlastnú podtriedu threading.Thread:

class ProfiledThread(threading.Thread):
    # Overrides threading.Thread.run()
    def run(self):
        profiler = cProfile.Profile()
        try:
            return profiler.runcall(threading.Thread.run, self)
        finally:
            profiler.dump_stats('myprofile-%d.profile' % (self.ident,))

a použiť túto triedu ProfiledThread namiesto štandardnej. Mohlo by vám to poskytnúť väčšiu flexibilitu, ale nie'som si istý, či sa to oplatí, najmä ak používate kód tretej strany, ktorý by vašu triedu nepoužíval.

Komentáre (6)

Vo Virtaal's source je'veľmi užitočná trieda a dekorátor, ktoré môžu veľmi uľahčiť profilovanie (aj pre konkrétne metódy/funkcie). Výstup sa potom dá veľmi pohodlne prezerať v KCacheGrinde.

Komentáre (1)