Qual é o equivalente em Python das funções tic e toc do Matlab ?
tic = timeit.default_timer(); (U,S,V) = np.linalg.svd(A); toc = timeit.default_timer()
então print toc-tic
.
Qual é o equivalente em Python das funções tic e toc do Matlab ?
tic = timeit.default_timer(); (U,S,V) = np.linalg.svd(A); toc = timeit.default_timer()
então print toc-tic
.
Respostas:
Além do timeit
que o ThiefMaster mencionou, uma maneira simples de fazer isso é apenas (após a importação time
):
t = time.time()
# do stuff
elapsed = time.time() - t
Tenho uma classe auxiliar que gosto de usar:
class Timer(object):
def __init__(self, name=None):
self.name = name
def __enter__(self):
self.tstart = time.time()
def __exit__(self, type, value, traceback):
if self.name:
print('[%s]' % self.name,)
print('Elapsed: %s' % (time.time() - self.tstart))
Ele pode ser usado como um gerenciador de contexto:
with Timer('foo_stuff'):
# do some foo
# do some stuff
Às vezes, acho essa técnica mais conveniente do que timeit
- tudo depende do que você deseja medir.
time
comando unix para medir tempos de execução de programas desde sempre, e esse método replica isso dentro do código Python. Não vejo nada de errado nisso, desde que seja a ferramenta certa para o trabalho. timeit
nem sempre é isso, e um profiler é uma solução muito mais pesada para a maioria das necessidades
print 'Elapsed: %.2f seconds % (time.time() - self.tstart)'
. É difícil entender sem o% .2f. Obrigado pela ótima ideia.
elapsed = t - time.time()
, em vez de elapsed = time.time() - t
. No último, decorrido será negativo. Eu sugeri essa mudança como uma edição.
elapsed = time.time() - t
é a forma que sempre produz um valor positivo.
Eu tive a mesma pergunta quando migrei para python do Matlab. Com a ajuda deste tópico, fui capaz de construir um análogo exato do Matlab tic()
e toc()
funções. Basta inserir o código a seguir na parte superior do seu script.
import time
def TicTocGenerator():
# Generator that returns time differences
ti = 0 # initial time
tf = time.time() # final time
while True:
ti = tf
tf = time.time()
yield tf-ti # returns the time difference
TicToc = TicTocGenerator() # create an instance of the TicTocGen generator
# This will be the main function through which we define both tic() and toc()
def toc(tempBool=True):
# Prints the time difference yielded by generator instance TicToc
tempTimeInterval = next(TicToc)
if tempBool:
print( "Elapsed time: %f seconds.\n" %tempTimeInterval )
def tic():
# Records a time in TicToc, marks the beginning of a time interval
toc(False)
É isso aí! Agora estamos prontos para usar totalmente tic()
e toc()
exatamente como no Matlab. Por exemplo
tic()
time.sleep(5)
toc() # returns "Elapsed time: 5.00 seconds."
Na verdade, isso é mais versátil do que as funções integradas do Matlab. Aqui, você pode criar outra instância do TicTocGenerator
para controlar várias operações ou apenas para cronometrar as coisas de forma diferente. Por exemplo, enquanto cronometramos um script, agora podemos cronometrar cada parte do script separadamente, bem como o script inteiro. (Vou dar um exemplo concreto)
TicToc2 = TicTocGenerator() # create another instance of the TicTocGen generator
def toc2(tempBool=True):
# Prints the time difference yielded by generator instance TicToc2
tempTimeInterval = next(TicToc2)
if tempBool:
print( "Elapsed time 2: %f seconds.\n" %tempTimeInterval )
def tic2():
# Records a time in TicToc2, marks the beginning of a time interval
toc2(False)
Agora você deve ser capaz de cronometrar duas coisas distintas: No exemplo a seguir, cronometramos o script total e partes de um script separadamente.
tic()
time.sleep(5)
tic2()
time.sleep(3)
toc2() # returns "Elapsed time 2: 5.00 seconds."
toc() # returns "Elapsed time: 8.00 seconds."
Na verdade, você nem precisa usar tic()
cada vez. Se você tem uma série de comandos que deseja cronometrar, pode escrever
tic()
time.sleep(1)
toc() # returns "Elapsed time: 1.00 seconds."
time.sleep(2)
toc() # returns "Elapsed time: 2.00 seconds."
time.sleep(3)
toc() # returns "Elapsed time: 3.00 seconds."
# and so on...
Espero que isso seja útil.
O melhor análogo absoluto de tic e toc seria simplesmente defini-los em python.
def tic():
#Homemade version of matlab tic and toc functions
import time
global startTime_for_tictoc
startTime_for_tictoc = time.time()
def toc():
import time
if 'startTime_for_tictoc' in globals():
print "Elapsed time is " + str(time.time() - startTime_for_tictoc) + " seconds."
else:
print "Toc: start time not set"
Então você pode usá-los como:
tic()
# do stuff
toc()
tic
e toc
, que o Matlab suporta. Um pouco mais de sofisticação seria necessário.
import time
externa de ambas as funções, já que pode levar algum tempo.
tic
empurrar e toc
sair dela.
timeit.default_timer()
é melhor do que time.time()
porque time.clock()
pode ser mais apropriado dependendo do sistema operacional
Normalmente, IPython de %time
, %timeit
, %prun
e %lprun
(caso tenha line_profiler
instalado) satisfazer as minhas necessidades de perfis muito bem. No entanto, um caso de uso para tic-toc
funcionalidade semelhante surgiu quando tentei traçar o perfil de cálculos que eram dirigidos interativamente, ou seja, pelo movimento do mouse do usuário em uma GUI. Achei que enviar spam para tic
s e toc
s nas fontes enquanto testava interativamente seria a maneira mais rápida de revelar os gargalos. Fui com a Timer
aula de Eli Bendersky , mas não fiquei muito feliz, pois me obrigou a alterar a indentação do meu código, o que pode ser inconveniente em alguns editores e confunde o sistema de controle de versão. Além disso, pode haver a necessidade de medir o tempo entre pontos em diferentes funções, o que não funcionaria com owith
declaração. Depois de tentar muita inteligência Python, aqui está a solução simples que achei que funcionou melhor:
from time import time
_tstart_stack = []
def tic():
_tstart_stack.append(time())
def toc(fmt="Elapsed: %s s"):
print fmt % (time() - _tstart_stack.pop())
Uma vez que isso funciona empurrando os tempos iniciais em uma pilha, funcionará corretamente para vários níveis de tic
s e toc
s. Ele também permite alterar a string de formato da toc
instrução para exibir informações adicionais, o que eu gostei na Timer
aula de Eli .
Por algum motivo, fiquei preocupado com a sobrecarga de uma implementação Python pura, então testei um módulo de extensão C também:
#include <Python.h>
#include <mach/mach_time.h>
#define MAXDEPTH 100
uint64_t start[MAXDEPTH];
int lvl=0;
static PyObject* tic(PyObject *self, PyObject *args) {
start[lvl++] = mach_absolute_time();
Py_RETURN_NONE;
}
static PyObject* toc(PyObject *self, PyObject *args) {
return PyFloat_FromDouble(
(double)(mach_absolute_time() - start[--lvl]) / 1000000000L);
}
static PyObject* res(PyObject *self, PyObject *args) {
return tic(NULL, NULL), toc(NULL, NULL);
}
static PyMethodDef methods[] = {
{"tic", tic, METH_NOARGS, "Start timer"},
{"toc", toc, METH_NOARGS, "Stop timer"},
{"res", res, METH_NOARGS, "Test timer resolution"},
{NULL, NULL, 0, NULL}
};
PyMODINIT_FUNC
inittictoc(void) {
Py_InitModule("tictoc", methods);
}
Isso é para MacOSX e omiti o código para verificar se lvl
está fora dos limites por questão de brevidade. Embora tictoc.res()
produza uma resolução de cerca de 50 nanossegundos em meu sistema, descobri que o jitter de medir qualquer instrução Python está facilmente na faixa de microssegundos (e muito mais quando usado no IPython). Nesse ponto, a sobrecarga da implementação Python torna-se insignificante, de modo que pode ser usada com a mesma confiança da implementação C.
Descobri que a utilidade da tic-toc
abordagem -é praticamente limitada a blocos de código que levam mais de 10 microssegundos para serem executados. Abaixo disso, estratégias de média como em timeit
são necessárias para obter uma medição fiel.
Você pode usar tic
e toc
de ttictoc
. Instale com
pip install ttictoc
E basta importá-los em seu script da seguinte forma
from ttictoc import tic,toc
tic()
# Some code
print(toc())
Acabei de criar um módulo [tictoc.py] para obter tic tocs aninhados, que é o que o Matlab faz.
from time import time
tics = []
def tic():
tics.append(time())
def toc():
if len(tics)==0:
return None
else:
return time()-tics.pop()
E funciona assim:
from tictoc import tic, toc
# This keeps track of the whole process
tic()
# Timing a small portion of code (maybe a loop)
tic()
# -- Nested code here --
# End
toc() # This returns the elapse time (in seconds) since the last invocation of tic()
toc() # This does the same for the first tic()
Espero que ajude.
Dê uma olhada no timeit
módulo. Não é realmente equivalente, mas se o código que você deseja cronometrar estiver dentro de uma função, você pode usá-lo facilmente.
timeit
é melhor para benchmarks. Não precisa ser uma única função, você pode passar instruções abritariamente complexas.
pip install easy-tictoc
No código:
from tictoc import tic, toc
tic()
#Some code
toc()
Isenção de responsabilidade: sou o autor desta biblioteca.
Isso também pode ser feito usando um invólucro. Maneira muito geral de marcar o tempo.
O wrapper neste código de exemplo envolve qualquer função e imprime a quantidade de tempo necessária para executar a função:
def timethis(f):
import time
def wrapped(*args, **kwargs):
start = time.time()
r = f(*args, **kwargs)
print "Executing {0} took {1} seconds".format(f.func_name, time.time()-start)
return r
return wrapped
@timethis
def thistakestime():
for x in range(10000000):
pass
thistakestime()
Mudei um pouco a resposta de @Eli Bendersky para usar o ctor __init__()
e o dtor __del__()
para fazer o tempo, para que possa ser usado de maneira mais conveniente sem recuar o código original:
class Timer(object):
def __init__(self, name=None):
self.name = name
self.tstart = time.time()
def __del__(self):
if self.name:
print '%s elapsed: %.2fs' % (self.name, time.time() - self.tstart)
else:
print 'Elapsed: %.2fs' % (time.time() - self.tstart)
Para usar, basta colocar Timer ("blahblah") no início de algum escopo local. O tempo decorrido será impresso no final do escopo:
for i in xrange(5):
timer = Timer("eigh()")
x = numpy.random.random((4000,4000));
x = (x+x.T)/2
numpy.linalg.eigh(x)
print i+1
timer = None
Ele imprime:
1
eigh() elapsed: 10.13s
2
eigh() elapsed: 9.74s
3
eigh() elapsed: 10.70s
4
eigh() elapsed: 10.25s
5
eigh() elapsed: 11.28s
timer
não é excluída após a última chamada, se qualquer outro código segue após o for
loop. Para obter o último valor do temporizador, deve-se excluir ou sobrescrever o timer
after the for
loop, por exemplo, via timer = None
.
Atualizando a resposta de Eli para Python 3:
class Timer(object):
def __init__(self, name=None, filename=None):
self.name = name
self.filename = filename
def __enter__(self):
self.tstart = time.time()
def __exit__(self, type, value, traceback):
message = 'Elapsed: %.2f seconds' % (time.time() - self.tstart)
if self.name:
message = '[%s] ' % self.name + message
print(message)
if self.filename:
with open(self.filename,'a') as file:
print(str(datetime.datetime.now())+": ",message,file=file)
Assim como o de Eli, ele pode ser usado como um gerenciador de contexto:
import time
with Timer('Count'):
for i in range(0,10_000_000):
pass
Resultado:
[Count] Elapsed: 0.27 seconds
Também o atualizei para imprimir as unidades de tempo relatadas (segundos) e cortar o número de dígitos conforme sugerido por Can, e com a opção de também anexar a um arquivo de log. Você deve importar data e hora para usar o recurso de registro:
import time
import datetime
with Timer('Count', 'log.txt'):
for i in range(0,10_000_000):
pass
Com base nas respostas de Stefan e antonimmo, acabei colocando
def Tictoc():
start_stack = []
start_named = {}
def tic(name=None):
if name is None:
start_stack.append(time())
else:
start_named[name] = time()
def toc(name=None):
if name is None:
start = start_stack.pop()
else:
start = start_named.pop(name)
elapsed = time() - start
return elapsed
return tic, toc
em um utils.py
módulo, e eu o uso com um
from utils import Tictoc
tic, toc = Tictoc()
Deste jeito
tic()
, toc()
e ninho-los como em Matlabtic(1)
, toc(1)
ou tic('very-important-block')
, toc('very-important-block')
e temporizadores com nomes diferentes não irá interferir(aqui toc não imprime o tempo decorrido, mas o retorna.)
tic = time.time()
etoc = time.time()
,print toc-tic, 'sec Elapsed'
como o pessoal disse abaixo, porém,timeit
é mais robusto.