Aqui estão minhas descobertas depois de passar por muitas boas respostas aqui, além de alguns outros artigos.
Primeiro, se você estiver debatendo entre timeit
e time.time
, o timeit
tem duas vantagens:
timeit
seleciona o melhor timer disponível na sua versão do SO e Python.
timeit
desativa a coleta de lixo, no entanto, isso não é algo que você pode ou não querer.
Agora, o problema é que timeit
não é tão simples de usar, porque ele precisa de configuração e as coisas ficam feias quando você tem um monte de importações. Idealmente, você só quer um decorador ou usa o with
bloco e mede o tempo. Infelizmente, não há nada embutido disponível para isso, então você tem duas opções:
Opção 1: usar a biblioteca de orçamento
O timebudget é uma biblioteca versátil e muito simples que você pode usar apenas em uma linha de código após a instalação do pip.
@timebudget # Record how long this function takes
def my_method():
# my code
Opção 2: use o módulo de código diretamente
Criei abaixo um pequeno módulo utilitário.
# utils.py
from functools import wraps
import gc
import timeit
def MeasureTime(f, no_print=False, disable_gc=False):
@wraps(f)
def _wrapper(*args, **kwargs):
gcold = gc.isenabled()
if disable_gc:
gc.disable()
start_time = timeit.default_timer()
try:
result = f(*args, **kwargs)
finally:
elapsed = timeit.default_timer() - start_time
if disable_gc and gcold:
gc.enable()
if not no_print:
print('"{}": {}s'.format(f.__name__, elapsed))
return result
return _wrapper
class MeasureBlockTime:
def __init__(self,name="(block)", no_print=False, disable_gc=False):
self.name = name
self.no_print = no_print
self.disable_gc = disable_gc
def __enter__(self):
self.gcold = gc.isenabled()
if self.disable_gc:
gc.disable()
self.start_time = timeit.default_timer()
def __exit__(self,ty,val,tb):
self.elapsed = timeit.default_timer() - self.start_time
if self.disable_gc and self.gcold:
gc.enable()
if not self.no_print:
print('Function "{}": {}s'.format(self.name, self.elapsed))
return False #re-raise any exceptions
Agora você pode cronometrar qualquer função colocando um decorador à sua frente:
import utils
@utils.MeasureTime
def MyBigFunc():
#do something time consuming
for i in range(10000):
print(i)
Se você quiser cronometrar parte do código, basta colocá-lo dentro do with
bloco:
import utils
#somewhere in my code
with utils.MeasureBlockTime("MyBlock"):
#do something time consuming
for i in range(10000):
print(i)
# rest of my code
Vantagens:
Existem várias versões com suporte parcial, por isso quero destacar alguns destaques:
- Use o timer de timeit em vez de time.time pelos motivos descritos anteriormente.
- Você pode desativar o GC durante o tempo, se desejar.
- O Decorator aceita funções com parâmetros nomeados ou não nomeados.
- Capacidade de desativar a impressão no tempo de bloco (use
with utils.MeasureBlockTime() as t
e depois t.elapsed
).
- Capacidade de manter o gc ativado para sincronização de bloco.