Medindo o tempo decorrido com o módulo Time

337

Com o módulo Time em python, é possível medir o tempo decorrido? Se sim, como faço isso?

Eu preciso fazer isso para que, se o cursor estiver em um widget por um determinado período, um evento acontecer.

rectangletangle
fonte
3
NB que qualquer resposta usando time.time()está incorreta. O exemplo mais simples é se a hora do sistema é alterada durante o período de medição.
precisa saber é
Para sua pergunta original sobre o disparo de um evento se um cursor permanecer por um certo período em um widget, docs.python.org/3/library/threading.html fornece tudo o que você precisa, eu acho. Multithreading e uma variável de condição com tempo limite podem ser uma das soluções. Suas circunstâncias, no entanto, não são claras no momento para responder.
Tora
2
Não há razão para que alguém deva estar usando time.time()para medir o tempo decorrido no python moderno (afetado por alterações manuais, desvio, segundos bissextos etc.). Esta resposta abaixo precisa ser maior, considerando que esta pergunta é agora o principal resultado no Google para medir o tempo decorrido.
NPras
Você também pode medir o tempo com o criador de perfil cProfile : docs.python.org/3/library/profile.html#module-cProfile stackoverflow.com/questions/582336/…
Anton Tarasenko
11
@NPras esquece "python moderno". Sempre foi incorreto usar time.time().
OrangeDog

Respostas:

514
start_time = time.time()
# your code
elapsed_time = time.time() - start_time

Você também pode escrever um decorador simples para simplificar a medição do tempo de execução de várias funções:

import time
from functools import wraps

PROF_DATA = {}

def profile(fn):
    @wraps(fn)
    def with_profiling(*args, **kwargs):
        start_time = time.time()

        ret = fn(*args, **kwargs)

        elapsed_time = time.time() - start_time

        if fn.__name__ not in PROF_DATA:
            PROF_DATA[fn.__name__] = [0, []]
        PROF_DATA[fn.__name__][0] += 1
        PROF_DATA[fn.__name__][1].append(elapsed_time)

        return ret

    return with_profiling

def print_prof_data():
    for fname, data in PROF_DATA.items():
        max_time = max(data[1])
        avg_time = sum(data[1]) / len(data[1])
        print "Function %s called %d times. " % (fname, data[0]),
        print 'Execution time max: %.3f, average: %.3f' % (max_time, avg_time)

def clear_prof_data():
    global PROF_DATA
    PROF_DATA = {}

Uso:

@profile
def your_function(...):
    ...

Você pode criar um perfil para mais de uma função simultaneamente. Em seguida, para imprimir as medidas, chame o print_prof_data ():

Vadim Shender
fonte
11
Você também pode dar uma olhada em profilehooks pip install profilehooks , e sua página inicial aqui
pjama
11
Observe que, desde o Python 3.3, é provável que você deva usá-lo em time.monotonic()vez de time.time()medir tempos limite ou durações. docs.python.org/3/library/time.html#time.monotonic
Debilski
39
Vale a pena acrescentar / observar aqui que a unidade de medida do tempo decorrido será de segundos.
Eric Kramer
4
@EricKramer obrigado! uma enorme mina de animais de estimação, explicando as medidas sem definir a unidade de medida. E como um cara do .NET mergulhando os pés no Python pela primeira vez, pensei automaticamente em "milissegundos".
precisa
2
Não funciona se (por exemplo) o relógio do sistema foi alterado e pode não ter resolução de subsegundo. Resposta correta: stackoverflow.com/a/47637891/476716
OrangeDog
97

time.time() fará o trabalho.

import time

start = time.time()
# run your code
end = time.time()

elapsed = end - start

Você pode olhar para esta pergunta, mas não acho que seja necessário.

lalli
fonte
6
Sim, o tempo está em segundos
Eric Kramer
Você deve alterar start para start_time.
Zoran Pandovski em 30/01
time.time()é uma péssima idéia, pois o relógio do sistema pode ser redefinido, o que fará você voltar no tempo. time.monotonic()cuida disso (monotônico = apenas avança). time.perf_counter()também é monotônico, mas com precisão ainda mais alta, portanto, isso é recomendado para o relógio de parede.
xjcl
75

Para usuários que desejam uma melhor formatação,

import time
start_time = time.time()
# your script
elapsed_time = time.time() - start_time
time.strftime("%H:%M:%S", time.gmtime(elapsed_time))

será impresso por 2 segundos:

'00:00:02'

e por 7 minutos um segundo:

'00:07:01'

note que a unidade de tempo mínima com gmtime é segundos. Se você precisar de microssegundos, considere o seguinte:

import datetime
start = datetime.datetime.now()
# some code
end = datetime.datetime.now()
elapsed = end - start
print(elapsed)
# or
print(elapsed.seconds,":",elapsed.microseconds) 

documentação do strftime

Rutger Hofste
fonte
11
Obrigado pela sua resposta, o que me inspira. Vou usar e = time.time() - start_time ; print("%02d:%02d:%02d" % (e // 3600, (e % 3600 // 60), (e % 60 // 1)))que produz quase o mesmo, além de cobrir a situação decorrida mais de 24 horas.
Tora
@Tora, convém verificar "{}". Format () em vez de% 02d para problemas futuros de compatibilidade.
Rutger Hofste 19/0318
2
obrigado! Agora estou me acostumando com o novo. '{: 02d}: {: 02d}: {: 02d}'. Formato (e // 3600, (e% 3600 // 60), e% 60)
Tora
você pode usar time.monotonic()como nas outras respostas?
endolith
elapsed.secondsestará incorreto se a duração for maior que um dia. Você quer elapsed.total_seconds()ser resiliente
Ash Berlin-Taylor
51

Para obter a melhor medida do tempo decorrido (desde o Python 3.3), use time.perf_counter().

Retorne o valor (em segundos fracionários) de um contador de desempenho, ou seja, um relógio com a maior resolução disponível para medir uma curta duração. Inclui o tempo decorrido durante o sono e abrange todo o sistema. O ponto de referência do valor retornado é indefinido, de modo que apenas a diferença entre os resultados de chamadas consecutivas seja válida.

Para medições na ordem de horas / dias, você não se importa com a resolução de menos de um segundo time.monotonic().

Retorne o valor (em segundos fracionários) de um relógio monotônico, ou seja, um relógio que não pode retroceder. O relógio não é afetado pelas atualizações do relógio do sistema. O ponto de referência do valor retornado é indefinido, de modo que apenas a diferença entre os resultados de chamadas consecutivas seja válida.

Em muitas implementações, elas podem realmente ser a mesma coisa.

Antes do 3.3, você está preso time.clock().

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.


Atualização para Python 3.7

O novo no Python 3.7 é o PEP 564 - Adicione novas funções de tempo com resolução de nanossegundos.

O uso deles pode eliminar ainda mais os erros de arredondamento e de ponto flutuante, especialmente se você estiver medindo períodos muito curtos, ou se seu aplicativo (ou máquina Windows) estiver demorando.

A resolução começa a falhar perf_counter()após cerca de 100 dias. Por exemplo, após um ano de atividade, o menor intervalo (maior que 0) que ele pode medir será maior do que quando foi iniciado.


Atualização para Python 3.8

time.clock agora se foi.

OrangeDog
fonte
"Em muitas implementações, elas podem realmente ser a mesma coisa." É verdade que, no meu PC Linux Mint, time.monotonic () e time.perf_counter () parecem retornar valores idênticos.
xjcl
7

Por um longo período.

import time
start_time = time.time()
...
e = int(time.time() - start_time)
print('{:02d}:{:02d}:{:02d}'.format(e // 3600, (e % 3600 // 60), e % 60))

imprimiria

00:03:15

se mais de 24 horas

25:33:57

Isso é inspirado na resposta de Rutger Hofste. Obrigado Rutger!

Tora
fonte
6

Você precisa importar o horário e, em seguida, usar o método time.time () para saber o horário atual.

import time

start_time=time.time() #taking current time as starting time

#here your code

elapsed_time=time.time()-start_time #again taking current time - starting time 
Nurul Akter Towhid
fonte
3

Outra boa maneira de cronometrar as coisas é usar a estrutura with python.

com estrutura está chamando automaticamente __enter__ e __exit__ métodos que é exatamente o que precisamos para as coisas temporais.

Vamos criar uma classe Timer .

from time import time

class Timer():
    def __init__(self, message):
        self.message = message
    def __enter__(self):
        self.start = time()
        return None  # could return anything, to be used like this: with Timer("Message") as value:
    def __exit__(self, type, value, traceback):
        elapsed_time = (time() - self.start) * 1000
        print(self.message.format(elapsed_time))

Então, pode-se usar a classe Timer como esta:

with Timer("Elapsed time to compute some prime numbers: {}ms"):
    primes = []
    for x in range(2, 500):
        if not any(x % p == 0 for p in primes):
            primes.append(x)
    print("Primes: {}".format(primes))

O resultado é o seguinte:

Primes: [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89 , 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227 , 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 331, 337, 347, 349, 353, 359, 367, 373 , 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499]

Tempo decorrido para calcular alguns números primos: 5.01704216003418ms

TM
fonte
2

A resposta do Vadim Shender é ótima. Você também pode usar um decorador mais simples, como abaixo:

import datetime
def calc_timing(original_function):                            
    def new_function(*args,**kwargs):                        
        start = datetime.datetime.now()                     
        x = original_function(*args,**kwargs)                
        elapsed = datetime.datetime.now()                      
        print("Elapsed Time = {0}".format(elapsed-start))     
        return x                                             
    return new_function()  

@calc_timing
def a_func(*variables):
    print("do something big!")
Mohammad
fonte
1

Na programação, existem 2 maneiras principais de medir o tempo , com resultados diferentes:

>>> print(time.process_time()); time.sleep(10); print(time.process_time())
0.11751394000000001
0.11764988400000001  # took  0 seconds and a bit
>>> print(time.perf_counter()); time.sleep(10); print(time.perf_counter())
3972.465770326
3982.468109075       # took 10 seconds and a bit
  • Tempo do processador : é quanto tempo esse processo específico passa sendo executado ativamente na CPU. Dormir, aguardar uma solicitação da Web ou o horário em que apenas outros processos são executados não contribuirá para isso.

    • Usar time.process_time()
  • Hora do relógio de parede : refere-se a quanto tempo passou "em um relógio pendurado na parede", ou seja, fora do tempo real.

    • Usar time.perf_counter()

      • time.time() também mede o tempo do relógio de parede, mas pode ser redefinido, para que você possa voltar no tempo
      • time.monotonic() não pode ser redefinido (monotônico = avança apenas), mas tem menor precisão do que time.perf_counter()
xjcl
fonte
0

Aqui está uma atualização do código inteligente de Vadim Shender com saída tabular:

import collections
import time
from functools import wraps

PROF_DATA = collections.defaultdict(list)

def profile(fn):
    @wraps(fn)
    def with_profiling(*args, **kwargs):
        start_time = time.time()
        ret = fn(*args, **kwargs)
        elapsed_time = time.time() - start_time
        PROF_DATA[fn.__name__].append(elapsed_time)
        return ret
    return with_profiling

Metrics = collections.namedtuple("Metrics", "sum_time num_calls min_time max_time avg_time fname")

def print_profile_data():
    results = []
    for fname, elapsed_times in PROF_DATA.items():
        num_calls = len(elapsed_times)
        min_time = min(elapsed_times)
        max_time = max(elapsed_times)
        sum_time = sum(elapsed_times)
        avg_time = sum_time / num_calls
        metrics = Metrics(sum_time, num_calls, min_time, max_time, avg_time, fname)
        results.append(metrics)
    total_time = sum([m.sum_time for m in results])
    print("\t".join(["Percent", "Sum", "Calls", "Min", "Max", "Mean", "Function"]))
    for m in sorted(results, reverse=True):
        print("%.1f\t%.3f\t%d\t%.3f\t%.3f\t%.3f\t%s" % (100 * m.sum_time / total_time, m.sum_time, m.num_calls, m.min_time, m.max_time, m.avg_time, m.fname))
    print("%.3f Total Time" % total_time)
Steve
fonte