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?
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 <string>:1(<module>)
1000 0.051 0.000 0.051 0.000 euler048.py:2(<lambda>)
1 0.005 0.005 0.061 0.061 euler048.py:2(<module>)
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](
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.