Что такое Python-эквивалент функций tic и toc в Matlab ?
tic = timeit.default_timer(); (U,S,V) = np.linalg.svd(A); toc = timeit.default_timer()
then print toc-tic
.
Что такое Python-эквивалент функций tic и toc в Matlab ?
tic = timeit.default_timer(); (U,S,V) = np.linalg.svd(A); toc = timeit.default_timer()
then print toc-tic
.
Ответы:
Помимо timeit
упомянутого ThiefMaster, простой способ сделать это (после импорта time
):
t = time.time()
# do stuff
elapsed = time.time() - t
У меня есть вспомогательный класс, который я люблю использовать:
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))
Его можно использовать как менеджер контекста:
with Timer('foo_stuff'):
# do some foo
# do some stuff
Иногда я нахожу этот метод более удобным, чем timeit
- все зависит от того, что вы хотите измерить.
time
для измерения времени выполнения программ, и этот метод воспроизводит это внутри кода Python. Я не вижу в этом ничего плохого, если это правильный инструмент для работы. timeit
не всегда так, и профилировщик - гораздо более тяжелое решение для большинства нужд
print 'Elapsed: %.2f seconds % (time.time() - self.tstart)'
. Трудно понять без% .2f. Спасибо за отличную идею.
elapsed = t - time.time()
, а не elapsed = time.time() - t
. В последнем истекший будет отрицательным. Я предложил это изменение как правку.
elapsed = time.time() - t
это форма, которая всегда дает положительное значение.
У меня был такой же вопрос, когда я перешел на Python с Matlab. С помощью этой ветки я смог построить точный аналог Matlab tic()
и toc()
functions. Просто вставьте следующий код в начало вашего скрипта.
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)
Это оно! Теперь мы готовы в полной мере использовать tic()
и toc()
так же , как в Matlab. Например
tic()
time.sleep(5)
toc() # returns "Elapsed time: 5.00 seconds."
Собственно, это более универсально, чем встроенные функции Matlab. Здесь вы можете создать еще один экземпляр TicTocGenerator
для отслеживания нескольких операций или просто для другого времени. Например, при хронометрировании скрипта теперь мы можем синхронизировать каждый фрагмент скрипта отдельно, а также весь скрипт. (Приведу конкретный пример)
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)
Теперь у вас должна быть возможность синхронизировать две отдельные вещи: В следующем примере мы синхронизируем весь сценарий и части сценария отдельно.
tic()
time.sleep(5)
tic2()
time.sleep(3)
toc2() # returns "Elapsed time 2: 5.00 seconds."
toc() # returns "Elapsed time: 8.00 seconds."
Собственно, вам даже не нужно tic()
каждый раз пользоваться. Если у вас есть серия команд, которые вы хотите отсрочить, вы можете написать
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...
Я надеюсь, что это поможет.
Лучшим аналогом tic и toc было бы просто определить их в 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"
Затем вы можете использовать их как:
tic()
# do stuff
toc()
tic
и toc
, которое поддерживает Matlab. Потребуется немного больше изощренности.
import time
внешнюю часть обеих функций, поскольку это может занять некоторое время.
tic
push к нему и выталкивать toc
из него.
timeit.default_timer()
лучше, чем time.time()
потому, что time.clock()
может быть более подходящим в зависимости от ОС
Обычно IPython - х %time
, %timeit
, %prun
и %lprun
(если таковой line_profiler
установлен) удовлетворяет мои потребности профилирующие достаточно хорошо. Однако вариант использования tic-toc
-подобной функциональности возник, когда я попытался профилировать вычисления, которые выполнялись интерактивно, то есть движением мыши пользователя в графическом интерфейсе. Я чувствовал , как спам tic
s и toc
S в источниках во время тестирования в интерактивном режиме будет самым быстрым способом выявить узкие места. Я пошел с Timer
классом Эли Бендерски , но не был полностью доволен, так как мне потребовалось изменить отступы моего кода, что может быть неудобно в некоторых редакторах и сбивать с толку систему контроля версий. Более того, может возникнуть необходимость в измерении времени между точками в разных функциях, что не будет работать сwith
заявление. Попробовав много хитрости Python, я нашел простое решение, которое работает лучше всего:
from time import time
_tstart_stack = []
def tic():
_tstart_stack.append(time())
def toc(fmt="Elapsed: %s s"):
print fmt % (time() - _tstart_stack.pop())
Поскольку это работает, помещая время начала в стек, он будет работать правильно для нескольких уровней tic
s и toc
s. Это также позволяет изменить строку формата toc
оператора для отображения дополнительной информации, которая мне понравилась в Timer
классе Эли .
По какой-то причине меня беспокоили накладные расходы на чистую реализацию Python, поэтому я также протестировал модуль расширения C:
#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);
}
Это для MacOSX, и я пропустил код, чтобы проверить, lvl
выходит ли он за рамки для краткости. Хотя tictoc.res()
в моей системе это дает разрешение около 50 наносекунд, я обнаружил, что дрожание при измерении любого оператора Python легко находится в диапазоне микросекунд (и намного больше при использовании из IPython). На этом этапе накладные расходы на реализацию Python становятся незначительными, поэтому ее можно использовать с той же уверенностью, что и реализация C.
Я обнаружил, что полезность tic-toc
-подхода практически ограничена блоками кода, выполнение которых занимает более 10 микросекунд. Ниже этого уровня timeit
требуются стратегии усреднения, подобные приведенному выше, для получения точных измерений.
Я только что создал модуль [tictoc.py] для создания вложенных тик-тактов, что и делает Matlab.
from time import time
tics = []
def tic():
tics.append(time())
def toc():
if len(tics)==0:
return None
else:
return time()-tics.pop()
А работает это так:
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()
Я надеюсь, что это помогает.
Взгляните на timeit
модуль. Это не совсем эквивалентно, но если код, который вы хотите разложить, находится внутри функции, вы можете легко его использовать.
timeit
лучше всего подходит для тестов. Это даже не обязательно должна быть одна функция, вы можете передавать чрезвычайно сложные операторы.
pip install easy-tictoc
В коде:
from tictoc import tic, toc
tic()
#Some code
toc()
Отказ от ответственности: я являюсь автором этой библиотеки.
Это также можно сделать с помощью обертки. Очень общий способ отсчета времени.
Обертка в этом примере кода обертывает любую функцию и выводит количество времени, необходимое для выполнения функции:
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()
Я немного изменил ответ @Eli __init__()
Bendersky, чтобы использовать ctor и dtor __del__()
для определения времени, чтобы его можно было использовать более удобно, не отступая от исходного кода:
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)
Чтобы использовать, просто поместите Timer ("blahblah") в начало некоторой локальной области видимости. Истекшее время будет напечатано в конце области:
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
Он распечатывает:
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
она не удаляется после последнего вызова, если после for
цикла следует какой-либо другой код . Чтобы получить последнее значение таймера, нужно удалить или перезаписать timer
после for
цикла, например через timer = None
.
Обновление ответа Эли на 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)
Как и у Эли, его можно использовать как диспетчер контекста:
import time
with Timer('Count'):
for i in range(0,10_000_000):
pass
Вывод:
[Count] Elapsed: 0.27 seconds
Я также обновил его, чтобы распечатать единицы времени (секунды) и сократить количество цифр, как было предложено Can, а также с возможностью добавления в файл журнала. Вы должны импортировать datetime, чтобы использовать функцию ведения журнала:
import time
import datetime
with Timer('Count', 'log.txt'):
for i in range(0,10_000_000):
pass
Основываясь на ответах Стефана и Антониммо, я закончил тем, что
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
в utils.py
модуле, и я использую его с
from utils import Tictoc
tic, toc = Tictoc()
Сюда
tic()
, toc()
и вкладывать их как в Matlabtic(1)
, toc(1)
или tic('very-important-block')
, toc('very-important-block')
и таймеры с разными названиями не будут мешать(здесь toc не выводит истекшее время, а возвращает его.)
tic = time.time()
иtoc = time.time()
, то ,print toc-tic, 'sec Elapsed'
как люди говорили ниже, однако,timeit
является более надежным.