Como medir o tempo decorrido no Python?


1211

O que eu quero é começar a contar o tempo em algum lugar do meu código e obter o tempo passado, para medir o tempo que levou para executar poucas funções. Acho que estou usando o módulo timeit errado, mas os documentos são apenas confusos para mim.

import timeit

start = timeit.timeit()
print("hello")
end = timeit.timeit()
print(end - start)

Respostas:


1456

Se você deseja apenas medir o tempo decorrido do relógio de parede entre dois pontos, você pode usar time.time():

import time

start = time.time()
print("hello")
end = time.time()
print(end - start)

Isso fornece o tempo de execução em segundos.

Outra opção desde o 3.3 pode ser usar perf_counterou process_time, dependendo de seus requisitos. Antes do 3.3, era recomendado o uso time.clock(obrigado Amber ). No entanto, atualmente está obsoleto:

No Unix, retorne o tempo atual do processador como um número de ponto flutuante expresso em segundos. A precisão e, de fato, a própria definição do significado de "tempo do processador", depende da função C de mesmo nome.

No Windows, essa função retorna os segundos do relógio de parede decorridos desde a primeira chamada para essa função, como um número de ponto flutuante, com base na função Win32 QueryPerformanceCounter(). A resolução normalmente é melhor que um microssegundo.

Descontinuado desde a versão 3.3 : O comportamento desta função depende da plataforma: use perf_counter()ouprocess_time() , em vez disso , dependendo de seus requisitos, para ter um comportamento bem definido.


17
e para microssegundos, use datetime.time ()
Inca

110
(Para medição de desempenho, time.clock()é realmente preferido, uma vez que não pode ser interferido se o relógio do sistema fica confuso com, mas .time()não na sua maioria realizar a mesma finalidade.)
Âmbar

4
Eu acho que python -mtimeit é muito melhor como ele é executado mais vezes e é de construção como uma maneira nativa para medir o tempo em python
Visgean Skeloru

4
Existe uma boa maneira de converter o tempo de execução resultante em segundos para algo como HH: MM :: SS?
Danijel

12
@Danijel: print(timedelta(seconds=execution_time)). Embora seja uma pergunta separada.
jfs

688

Use em timeit.default_timervez de timeit.timeit. O primeiro fornece o melhor relógio disponível em sua plataforma e versão do Python automaticamente:

from timeit import default_timer as timer

start = timer()
# ...
end = timer()
print(end - start) # Time in seconds, e.g. 5.38091952400282

timeit.default_timer é atribuído a time.time () ou time.clock () dependendo do sistema operacional. No Python 3.3+, default_timer é time.perf_counter () em todas as plataformas. Veja Python - precisão time.clock () vs. time.time () - precisão?

Veja também:


28
Excelente resposta - usando timeit irá produzir resultados muito mais precisos, uma vez que irá automaticamente a conta para coisas como as diferenças de coleta de lixo e OS
lkgarrison

1
Isso dá tempo em ms ou segundos?
Katie

3
@KhushbooTiwari em segundos fracionários.
jfs

5
Eu acho que esta nota das necessidades oficiais de documentação a ser adicionadodefault_timer() measurations can be affected by other programs running on the same machine, so the best thing to do when accurate timing is necessary is to repeat the timing a few times and use the best time. The -r option is good for this; the default of 3 repetitions is probably enough in most cases. On Unix, you can use time.clock() to measure CPU time.
KGS

1
@KGS: A medição do desempenho é muito complicada de uma maneira sutil (é fácil enganar a si mesmo). Existem muitas outras observações que podem ser relevantes aqui. Siga os links na resposta. Você também pode estar interessado no perfmódulo (inexistente no momento da resposta) que fornece a mesma interface, mas às vezes difere das timeitdecisões do módulo sobre como medir o desempenho do tempo.
JFS

129

Apenas Python 3:

Como time.clock () está obsoleto no Python 3.3 , convém usar o tempo time.perf_counter()para todo o sistema ou time.process_time()para todo o processo, exatamente como você costumava usar time.clock():

import time

t = time.process_time()
#do some stuff
elapsed_time = time.process_time() - t

A nova função process_timenão incluirá o tempo decorrido durante o sono.


28
Use emtimeit.default_timer vez de time.perf_counter. O primeiro escolherá o cronômetro apropriado para medir o desempenho do tempo ajustado para sua plataforma e versão do Python. process_time()faz não inclui o tempo durante o sono e, portanto, não é apropriado para medir o tempo decorrido.
jfs

2
Estou usando a implementação sugerida por Pierre, os valores são fornecidos em segundos?
Ugotchi 12/08/16

Essa resposta parece fora de tópico (bem, a pergunta não era muito específica). Existem duas medidas de "tempo": o tempo do relógio de parede entre dois pontos, do consumo da CPU do processo.
Franklin Piat

87

Dada uma função que você gostaria de cronometrar,

test.py:

def foo(): 
    # print "hello"   
    return "hello"

a maneira mais fácil de usar timeité chamá-lo na linha de comando:

% python -mtimeit -s'import test' 'test.foo()'
1000000 loops, best of 3: 0.254 usec per loop

Não tente usar time.timeou time.clock(ingenuamente) comparar a velocidade das funções. Eles podem dar resultados enganosos .

PS. Não coloque instruções de impressão em uma função que deseja cronometrar; caso contrário, o tempo medido dependerá da velocidade do terminal .


65

É divertido fazer isso com um gerenciador de contexto que se lembra automaticamente da hora de início na entrada de um withbloco e congela a hora de término na saída do bloco. Com um pouco de truque, você pode até obter uma contagem de tempo decorrido dentro do bloco a partir da mesma função de gerenciador de contexto.

A biblioteca principal não tem isso (mas provavelmente deveria). Uma vez instalado, você pode fazer coisas como:

with elapsed_timer() as elapsed:
    # some lengthy code
    print( "midpoint at %.2f seconds" % elapsed() )  # time so far
    # other lengthy code

print( "all done at %.2f seconds" % elapsed() )

Aqui está o código do gerenciador de contexto suficiente para executar o truque:

from contextlib import contextmanager
from timeit import default_timer

@contextmanager
def elapsed_timer():
    start = default_timer()
    elapser = lambda: default_timer() - start
    yield lambda: elapser()
    end = default_timer()
    elapser = lambda: end-start

E algum código de demonstração executável:

import time

with elapsed_timer() as elapsed:
    time.sleep(1)
    print(elapsed())
    time.sleep(2)
    print(elapsed())
    time.sleep(3)

Observe que, por design dessa função, o valor de retorno de elapsed()é congelado na saída do bloco e outras chamadas retornam a mesma duração (de cerca de 6 segundos neste exemplo de brinquedo).


2
Outro exemplo de gerenciador de contexto: dabeaz.blogspot.fr/2010/02/…
Jérôme

1
@ Jérôme bom exemplo - eu adaptei-o como outra resposta - stackoverflow.com/a/41408510/243392 #
Brian

62

Tempo de medição em segundos:

from timeit import default_timer as timer
from datetime import timedelta

start = timer()
end = timer()
print(timedelta(seconds=end-start))

Saída :

0:00:01.946339

1
Esta é a resposta mais concisa com a saída mais limpa.
Dave Liu

56

Eu prefiro isso. timeitdoc é muito confuso.

from datetime import datetime 

start_time = datetime.now() 

# INSERT YOUR CODE 

time_elapsed = datetime.now() - start_time 

print('Time elapsed (hh:mm:ss.ms) {}'.format(time_elapsed))

Observe que não há formatação aqui, eu apenas escrevi hh:mm:ssna impressão para que se possa interpretartime_elapsed


Disseram-me que o timeit calcula o tempo da CPU, o datetime também leva em consideração o tempo da CPU usado? São a mesma coisa?
Sreehari R

3
É arriscado medir o tempo decorrido dessa maneira, porque datetime.now () pode mudar entre as duas chamadas por motivos como sincronização da hora da rede, alternância do horário de verão ou o usuário girando o relógio.
user1318499

45

Aqui está outra maneira de fazer isso:

>> from pytictoc import TicToc
>> t = TicToc() # create TicToc instance
>> t.tic() # Start timer
>> # do something
>> t.toc() # Print elapsed time
Elapsed time is 2.612231 seconds.

Comparando com a maneira tradicional:

>> from time import time
>> t1 = time()
>> # do something
>> t2 = time()
>> elapsed = t2 - t1
>> print('Elapsed time is %f seconds.' % elapsed)
Elapsed time is 2.612231 seconds.

Instalação:

pip install pytictoc

Consulte a página PyPi para mais detalhes.


13
Seria bom explicar a vantagem de usar essa biblioteca em relação a outras abordagens.
Hlg

A funcionalidade aninhada está realmente quebrada. Abri um problema descrevendo onde está o problema no código, mas o repositório não é mantido há um ano, então não esperaria uma alteração.
PetarMI

Acho o ninho um pouco confuso. Se eu me deparar t.tic()enterrado no código, cabe a mim o desenvolvedor manter uma lista mental de onde, na série, devo esperar que seja. Você se encontra montando ninhos ou apenas vários tictocs?
ScottieB

1
@PetarMI: Para sua informação, acabei de corrigir o problema ttictoc. Que bagunça eu tinha, mas deve estar bom agora.
H. Sánchez

33

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 timeite time.time, o timeittem duas vantagens:

  1. timeit seleciona o melhor timer disponível na sua versão do SO e Python.
  2. timeit desativa a coleta de lixo, no entanto, isso não é algo que você pode ou não querer.

Agora, o problema é que timeitnã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 withbloco 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 withbloco:

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:

  1. Use o timer de timeit em vez de time.time pelos motivos descritos anteriormente.
  2. Você pode desativar o GC durante o tempo, se desejar.
  3. O Decorator aceita funções com parâmetros nomeados ou não nomeados.
  4. Capacidade de desativar a impressão no tempo de bloco (use with utils.MeasureBlockTime() as te depois t.elapsed).
  5. Capacidade de manter o gc ativado para sincronização de bloco.

28

Usar time.timepara medir a execução fornece o tempo total de execução de seus comandos, incluindo o tempo de execução gasto por outros processos no seu computador. É a hora em que o usuário percebe, mas não é bom se você deseja comparar diferentes trechos de código / algoritmos / funções / ...

Mais informações em timeit:

Se você deseja uma visão mais profunda da criação de perfil:

Atualização : usei muito o http://pythonhosted.org/line_profiler/ durante o último ano e achei muito útil e recomendo usá-lo em vez do módulo de perfil do Pythons.


19

Aqui está uma pequena classe de timer que retorna a string "hh: mm: ss":

class Timer:
  def __init__(self):
    self.start = time.time()

  def restart(self):
    self.start = time.time()

  def get_time_hhmmss(self):
    end = time.time()
    m, s = divmod(end - self.start, 60)
    h, m = divmod(m, 60)
    time_str = "%02d:%02d:%02d" % (h, m, s)
    return time_str

Uso:

# Start timer
my_timer = Timer()

# ... do something

# Get time string:
time_hhmmss = my_timer.get_time_hhmmss()
print("Time elapsed: %s" % time_hhmmss )

# ... use the timer again
my_timer.restart()

# ... do something

# Get time:
time_hhmmss = my_timer.get_time_hhmmss()

# ... etc

17

Os módulos python cProfile e pstats oferecem grande suporte para medir o tempo decorrido em determinadas funções sem precisar adicionar nenhum código às funções existentes.

Por exemplo, se você tiver um script python timeFunctions.py:

import time

def hello():
    print "Hello :)"
    time.sleep(0.1)

def thankyou():
    print "Thank you!"
    time.sleep(0.05)

for idx in range(10):
    hello()

for idx in range(100):
    thankyou()

Para executar o criador de perfil e gerar estatísticas para o arquivo, basta executar:

python -m cProfile -o timeStats.profile timeFunctions.py

O que isso está fazendo é usar o módulo cProfile para criar um perfil de todas as funções no timeFunctions.py e coletar as estatísticas no arquivo timeStats.profile. Observe que não precisamos adicionar nenhum código ao módulo existente (timeFunctions.py) e isso pode ser feito com qualquer módulo.

Depois de ter o arquivo de estatísticas, você pode executar o módulo pstats da seguinte maneira:

python -m pstats timeStats.profile

Isso executa o navegador de estatísticas interativas, que oferece muitas funcionalidades interessantes. Para seu caso de uso específico, você pode apenas verificar as estatísticas de sua função. No nosso exemplo, verificar estatísticas para ambas as funções mostra o seguinte:

Welcome to the profile statistics browser.
timeStats.profile% stats hello
<timestamp>    timeStats.profile

         224 function calls in 6.014 seconds

   Random listing order was used
   List reduced from 6 to 1 due to restriction <'hello'>

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
       10    0.000    0.000    1.001    0.100 timeFunctions.py:3(hello)

timeStats.profile% stats thankyou
<timestamp>    timeStats.profile

         224 function calls in 6.014 seconds

   Random listing order was used
   List reduced from 6 to 1 due to restriction <'thankyou'>

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
      100    0.002    0.000    5.012    0.050 timeFunctions.py:7(thankyou)

O exemplo fictício não faz muito, mas dá uma idéia do que pode ser feito. A melhor parte dessa abordagem é que não preciso editar nenhum código existente para obter esses números e, obviamente, ajudar na criação de perfis.


Tudo isso está bem, mas AFAICT ainda mede o tempo da CPU, não o tempo do relógio de parede.
ShreevatsaR

1
Na verdade, há alguma confusão; parece que o cProfile verifica a hora do relógio de parede por padrão. Eu votei na sua resposta.
precisa

FYI: Se você conseguir, python -m pstats timeStats.profile ValueError: bad marshal data (unknown type code)verifique sua versão do python que está executando. Eu consegui isso quando corri python3 -m cProfile...e python -m pstats. Meu erro, mas me pegou por um segundo, então, eu queria compartilhar don't forget consistency. =)
JayRizzo 26/10

17

Aqui está outro gerenciador de contexto para o código de temporização -

Uso:

from benchmark import benchmark

with benchmark("Test 1+1"):
    1+1
=>
Test 1+1 : 1.41e-06 seconds

ou, se você precisar do valor do tempo

with benchmark("Test 1+1") as b:
    1+1
print(b.time)
=>
Test 1+1 : 7.05e-07 seconds
7.05233786763e-07

benchmark.py :

from timeit import default_timer as timer

class benchmark(object):

    def __init__(self, msg, fmt="%0.3g"):
        self.msg = msg
        self.fmt = fmt

    def __enter__(self):
        self.start = timer()
        return self

    def __exit__(self, *args):
        t = timer() - self.start
        print(("%s : " + self.fmt + " seconds") % (self.msg, t))
        self.time = t

Adaptado de http://dabeaz.blogspot.fr/2010/02/context-manager-for-timing-benchmarks.html


17

Use o módulo profiler. Dá um perfil muito detalhado.

import profile
profile.run('main()')

gera algo como:

          5 function calls in 0.047 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000    0.000    0.000 :0(exec)
        1    0.047    0.047    0.047    0.047 :0(setprofile)
        1    0.000    0.000    0.000    0.000 <string>:1(<module>)
        0    0.000             0.000          profile:0(profiler)
        1    0.000    0.000    0.047    0.047 profile:0(main())
        1    0.000    0.000    0.000    0.000 two_sum.py:2(twoSum)

Eu achei muito informativo.


1
O que é main()? Seria mais útil se você pudesse fornecer um exemplo de código simples.
Not2qubit 26/09/18

15

Eu gosto simples (python 3):

from timeit import timeit

timeit(lambda: print("hello"))

A saída é microssegundos para uma única execução:

2.430883963010274

Explicação : timeit executa a função anônima 1 milhão de vezes por padrão e o resultado é fornecido em segundos . Portanto, o resultado para uma única execução é a mesma quantidade, mas em microssegundos em média.


Para operações lentas , adicione um número menor de iterações ou você poderá esperar para sempre:

import time

timeit(lambda: time.sleep(1.5), number=1)

A saída é sempre em segundos para o número total de iterações:

1.5015795179999714

14

(Somente com Ipython), você pode usar % timeit para medir o tempo médio de processamento:

def foo():
    print "hello"

e depois:

%timeit foo()

o resultado é algo como:

10000 loops, best of 3: 27 µs per loop

4
Vale mencionar que é possível passar sinalizadores para% timeit, por exemplo -n especifica quantas vezes o código deve ser repetido.
raacer

11

Mais uma maneira de usar o timeit :

from timeit import timeit

def func():
    return 1 + 1

time = timeit(func, number=1)
print(time)

10

em python3:

from time import sleep, perf_counter as pc
t0 = pc()
sleep(1)
print(pc()-t0)

elegante e curto.


o que é isso? em?
KIC

9

Uma resposta super tardia, mas talvez sirva a um propósito para alguém. Esta é uma maneira de fazê-lo, que eu acho super limpa.

import time

def timed(fun, *args):
    s = time.time()
    r = fun(*args)
    print('{} execution took {} seconds.'.format(fun.__name__, time.time()-s))
    return(r)

timed(print, "Hello")

Lembre-se de que "print" é uma função no Python 3 e não no Python 2.7. No entanto, ele funciona com qualquer outra função. Felicidades!


Como posso imprimir tempos muito pequenos? Eu meio que estou recebendo 0.0sec sempre
Rowland Mtetezi

Você pode transformar isso em um decorador; isso parece ainda melhor para mim.
Daniel Moskovich 10/10

8

Você pode usar timeit.

Aqui está um exemplo de como testar naive_func que usa parâmetros usando o Python REPL:

>>> import timeit                                                                                         

>>> def naive_func(x):                                                                                    
...     a = 0                                                                                             
...     for i in range(a):                                                                                
...         a += i                                                                                        
...     return a                                                                                          

>>> def wrapper(func, *args, **kwargs):                                                                   
...     def wrapper():                                                                                    
...         return func(*args, **kwargs)                                                                  
...     return wrapper                                                                                    

>>> wrapped = wrapper(naive_func, 1_000)                                                                  

>>> timeit.timeit(wrapped, number=1_000_000)                                                              
0.4458435332577161  

Você não precisa da função wrapper se a função não tiver nenhum parâmetro.


1
A lambdaseria mais sucinto:print(timeit.timeit(lambda: naive_func(1_000), number=1_000_000))
Ciro Santilli escreveu

7

Também podemos converter tempo em tempo legível por humanos.

import time, datetime

start = time.clock()

def num_multi1(max):
    result = 0
    for num in range(0, 1000):
        if (num % 3 == 0 or num % 5 == 0):
            result += num

    print "Sum is %d " % result

num_multi1(1000)

end = time.clock()
value = end - start
timestamp = datetime.datetime.fromtimestamp(value)
print timestamp.strftime('%Y-%m-%d %H:%M:%S')

6

Eu criei uma biblioteca para isso, se você quiser medir uma função, você pode fazê-lo assim


from pythonbenchmark import compare, measure
import time

a,b,c,d,e = 10,10,10,10,10
something = [a,b,c,d,e]

@measure
def myFunction(something):
    time.sleep(0.4)

@measure
def myOptimizedFunction(something):
    time.sleep(0.2)

myFunction(input)
myOptimizedFunction(input)

https://github.com/Karlheinzniebuhr/pythonbenchmark


6

Para obter informações sobre todas as chamadas de função recursivamente, faça:

%load_ext snakeviz
%%snakeviz

Ele pega essas duas linhas de código em um notebook Jupyter e gera um bom diagrama interativo. Por exemplo:

insira a descrição da imagem aqui

Aqui está o código. Novamente, as duas linhas que começam com %são as únicas linhas de código extras necessárias para usar o snakeviz:

# !pip install snakeviz
%load_ext snakeviz
import glob
import hashlib

%%snakeviz

files = glob.glob('*.txt')
def print_files_hashed(files):
    for file in files:
        with open(file) as f:
            print(hashlib.md5(f.read().encode('utf-8')).hexdigest())
print_files_hashed(files)

Também parece possível executar o snakeviz fora dos notebooks. Mais informações no site da snakeviz .


2
import time

def getElapsedTime(startTime, units):
    elapsedInSeconds = time.time() - startTime
    if units == 'sec':
        return elapsedInSeconds
    if units == 'min':
        return elapsedInSeconds/60
    if units == 'hour':
        return elapsedInSeconds/(60*60)

2

Essa abordagem exclusiva baseada em classe oferece uma representação de sequência imprimível, arredondamento personalizável e acesso conveniente ao tempo decorrido como uma sequência ou flutuação. Foi desenvolvido com o Python 3.7.

import datetime
import timeit


class Timer:
    """Measure time used."""
    # Ref: https://stackoverflow.com/a/57931660/

    def __init__(self, round_ndigits: int = 0):
        self._round_ndigits = round_ndigits
        self._start_time = timeit.default_timer()

    def __call__(self) -> float:
        return timeit.default_timer() - self._start_time

    def __str__(self) -> str:
        return str(datetime.timedelta(seconds=round(self(), self._round_ndigits)))

Uso:

# Setup timer
>>> timer = Timer()

# Access as a string
>>> print(f'Time elapsed is {timer}.')
Time elapsed is 0:00:03.
>>> print(f'Time elapsed is {timer}.')
Time elapsed is 0:00:04.

# Access as a float
>>> timer()
6.841332235
>>> timer()
7.970274425

1

Avalie o tempo de execução de pequenos trechos de código.

Unidade de tempo : medida em segundos como um flutuador

import timeit
t = timeit.Timer('li = list(map(lambda x:x*2,[1,2,3,4,5]))')
t.timeit()
t.repeat()
>[1.2934070999999676, 1.3335035000000062, 1.422568500000125]

O método repeat () é uma conveniência para chamar timeit () várias vezes e retornar uma lista de resultados.

repeat(repeat=3

Com esta lista, podemos ter uma média de todos os tempos.

Por padrão, timeit () desativa temporariamente a coleta de lixo durante o tempo. time.Timer () resolve esse problema.

Prós:

timeit.Timer () torna horários independentes mais comparáveis. O gc pode ser um componente importante do desempenho da função que está sendo medida. Nesse caso, o gc (coletor de lixo) pode ser reativado como a primeira instrução na cadeia de instalação. Por exemplo:

timeit.Timer('li = list(map(lambda x:x*2,[1,2,3,4,5]))',setup='gc.enable()')

Docs do Python de origem !


1

Se você deseja programar funções de forma conveniente, pode usar um decorador simples:

def timing_decorator(func):
    def wrapper(*args, **kwargs):
        start = time.time()
        original_return_val = func(*args, **kwargs)
        end = time.time()
        print("time elapsed in ", func.__name__, ": ", end - start, sep='')
        return original_return_val

    return wrapper

Você pode usá-lo em uma função que deseja cronometrar assim:

@timing_decorator
def function_to_time():
    time.sleep(1)

Então, sempre que você ligar function_to_time, imprimirá quanto tempo levou e o nome da função que está sendo cronometrada.


1

com base na solução contextmanager fornecida por https://stackoverflow.com/a/30024601/5095636 , abaixo da versão gratuita lambda, pois o flake8 adverte sobre o uso de lambda conforme E731 :

from contextlib import contextmanager
from timeit import default_timer

@contextmanager
def elapsed_timer():
    start_time = default_timer()

    class _Timer():
      start = start_time
      end = default_timer()
      duration = end - start

    yield _Timer

    end_time = default_timer()
    _Timer.end = end_time
    _Timer.duration = end_time - start_time

teste:

from time import sleep

with elapsed_timer() as t:
    print("start:", t.start)
    sleep(1)
    print("end:", t.end)

t.start
t.end
t.duration

1

A maneira mais fácil de calcular a duração de uma operação:

import time

start_time = time.time()
print(time.ctime())

<operations, programs>

print('minutes: ',(time.time() - start_time)/60)

1

Aqui está um decorador com dicas bastante bem documentado e completo que eu uso como um utilitário geral:

from functools import wraps
from time import perf_counter
from typing import Any, Callable, Optional, TypeVar, cast

F = TypeVar("F", bound=Callable[..., Any])


def timer(prefix: Optional[str] = None, precision: int = 6) -> Callable[[F], F]:
    """Use as a decorator to time the execution of any function.

    Args:
        prefix: String to print before the time taken.
            Default is the name of the function.
        precision: How many decimals to include in the seconds value.

    Examples:
        >>> @timer()
        ... def foo(x):
        ...     return x
        >>> foo(123)
        foo: 0.000...s
        123
        >>> @timer("Time taken: ", 2)
        ... def foo(x):
        ...     return x
        >>> foo(123)
        Time taken: 0.00s
        123

    """
    def decorator(func: F) -> F:
        @wraps(func)
        def wrapper(*args: Any, **kwargs: Any) -> Any:
            nonlocal prefix
            prefix = prefix if prefix is not None else f"{func.__name__}: "
            start = perf_counter()
            result = func(*args, **kwargs)
            end = perf_counter()
            print(f"{prefix}{end - start:.{precision}f}s")
            return result
        return cast(F, wrapper)
    return decorator

Exemplo de uso:

from timer import timer


@timer(precision=9)
def takes_long(x: int) -> bool:
    return x in (i for i in range(x + 1))


print(takes_long(10**8))

Resultado:

takes_long: 4.942629056s
True

Os documentos podem ser verificados com:

$ python3 -m doctest --verbose -o=ELLIPSIS timer.py

E o tipo sugere com:

$ mypy timer.py

1
Isso é super legal, obrigado por compartilhar. Eu não encontrei a biblioteca de digitação ou a palavra-chave não-local - é divertido descobrir coisas novas para aprender. Estou tendo problemas envolvendo minha cabeça em torno deste: Callable[[AnyF], AnyF]. O que isso significa?
Danny

1
@ Danny No topo, eu defini o alias de tipo AnyFcomo significando Callable[..., Any], portanto, AnyFé uma função que pode pegar qualquer quantidade de qualquer tipo de argumento e retornar qualquer coisa. Então Callable[[AnyF], AnyF]iria expandir para Callable[[Callable[..., Any]], Callable[..., Any]]. Este é o tipo do valor de retorno de timeraka o tipo completo de decorator. É uma função que aceita qualquer tipo de função como único argumento e retorna qualquer tipo de função.
ruohola 03/06

1
Obrigada pelo esclarecimento! Ainda estou tentando entender completamente o interior dos decoradores. Isso ajudou muito!
Danny
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.