Medir o tempo de processamento com o módulo Timeit de Python.

O negócio

Usando o módulo timeit da biblioteca padrão Python, pode facilmente medir o tempo de execução de um processo no seu código. Isto é útil para uma verificação rápida.

Os dois casos seguintes serão aqui discutidos.

  • Medida num ficheiro Python:timeit.timeit(),timeit.repeat()
  • Medição com caderno de notas Jupyter:%timeit,%%timeit

Outra forma é usar o time.time() para medir o tempo decorrido no programa.

Medidas em ficheiros Python: timeit.timeit(), timeit.repeat()

Como exemplo, vamos medir o tempo de processamento de uma função simples, teste(n), que calcula a soma de n números consecutivos.

import timeit

def test(n):
    return sum(range(n))

n = 10000
loop = 1000

result = timeit.timeit('test(n)', globals=globals(), number=loop)
print(result / loop)
# 0.0002666301020071842

Se passar o código que pretende medir como uma string à função timeit.timeit(), será executado NÚMERO de vezes e o tempo que levou será devolvido.
O valor por defeito para o número é de 1.000.000. Note-se que se utilizar o valor por defeito para um processo moroso, este demorará muito tempo.

Ao passar globals() como argumentos globais, o código será executado no namespace global.
Sem isto, o teste de função e a variável n não são reconhecidos no exemplo acima.

O código a especificar pode ser um objecto chamável em vez de uma string, por isso pode ser especificado como uma expressão lambda sem argumentos; neste caso, o argumento global não precisa de ser especificado.

result = timeit.timeit(lambda: test(n), number=loop)
print(result / loop)
# 0.00027574066299712287

A unidade do resultado é de segundos. Aqui, o resultado é o tempo de processamento por execução dividido pelo número de execuções.

Se não dividir, o valor do resultado tornar-se-á simplesmente maior à medida que aumenta o número de execuções.

print(timeit.timeit(lambda: test(n), number=1))
print(timeit.timeit(lambda: test(n), number=10))
print(timeit.timeit(lambda: test(n), number=100))
# 0.0003999490290880203
# 0.0038685189792886376
# 0.03517670702422038

Usando a função timeit.repeat(), o timeit() pode ser executado repetidamente. O resultado será obtido como uma lista.

repeat = 5
print(timeit.repeat(lambda: test(n), repeat=repeat, number=100))
# [0.044914519996382296, 0.039663890027441084, 0.02868645201670006, 0.022745631984435022, 0.023260265996214002]

Medição com caderno de notas Jupyter:%timeit, %%timeit

Em Jupyter Notebook (IPython), pode usar os seguintes comandos mágicos; não há necessidade de importar o módulo timeit.

  • %timeit
  • %%timeit

%timeit

Em %timeit, especificar o código alvo separado por um espaço como argumentos de linha de comando.

Por defeito, o número e repetir em timeit.timeit() são determinados automaticamente. Pode também especificá-los com as opções -n e -r.

Os resultados são calculados como média e desvio padrão.

%timeit test(n)
# 259 µs ± 4.87 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

%timeit -r 3 -n 10000 test(n)
# 237 µs ± 6.44 µs per loop (mean ± std. dev. of 3 runs, 10000 loops each)

%%timeit

O comando mágico %%timeit pode ser usado para medir o tempo de processamento de uma célula inteira.

Como exemplo, vamos executar o mesmo processo utilizando o NumPy. As opções -n e -r podem ser omitidas.

Uma vez que medimos o tempo de processamento de toda a célula, o exemplo seguinte inclui o tempo para importar NumPy.

%%timeit -r 3 -n 10000
import numpy as np
a = np.arange(n)
np.sum(a)
# 19.7 µs ± 9.57 µs per loop (mean ± std. dev. of 3 runs, 10000 loops each)

Não há necessidade de especificar o código alvo como um argumento para %%timeit. Tudo o que tem de fazer é escrever %%timeit no início de uma célula, por isso é o mais fácil de usar.