Answers:
除了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
是始终产生正值的形式。
从Matlab迁移到python时,我遇到了同样的问题。借助该线程,我能够构建Matlab 和函数的精确模拟。只需在脚本顶部插入以下代码。tic()
toc()
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
。需要更多的复杂性。
import time
两个函数的外部,因为这可能会花费一些时间。
tic
设为列表,然后将其推入列表并从中toc
弹出。
timeit.default_timer()
比其更好的书,time.time()
因为它time.clock()
可能更适合于操作系统
通常情况下,IPython中的%time
,%timeit
,%prun
和%lprun
(如果已line_profiler
安装)满足我的需求剖析很好。但是,tic-toc
当我尝试分析交互驱动的计算时(即,由用户在GUI中的鼠标移动),出现了类似功能的用例。我觉得在交互式测试中在源中发送tic
s和toc
s 垃圾邮件是揭示瓶颈的最快方法。我参加了Eli Bendersky的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
语句的格式字符串以显示其他信息,这是我喜欢有关Eli的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
-approach的实用性实际上仅限于执行超过10微秒的代码块。在此之下,timeit
需要进行诸如in的平均策略才能获得忠实的度量。
我刚刚创建了一个模块[tictoc.py]来实现嵌套tic tocs,这是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()
希望对您有所帮助。
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 Bendersky的答案做了一些更改,以使用ctor __init__()
和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
。
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)
就像Eli一样,它可以用作上下文管理器:
import time
with Timer('Count'):
for i in range(0,10_000_000):
pass
输出:
[Count] Elapsed: 0.27 seconds
我还更新了它,以打印报告的时间单位(秒)并按照Can的建议修整位数,并可以选择附加到日志文件中。您必须导入日期时间才能使用日志记录功能:
import time
import datetime
with Timer('Count', 'log.txt'):
for i in range(0,10_000_000):
pass
基于Stefan和antonimmo的答案,我最终提出
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()
并将其嵌套在Matlab中tic(1)
,toc(1)
或tic('very-important-block')
,toc('very-important-block')
并且具有不同名称的计时器不会干扰(这里toc不打印经过的时间,而是返回经过的时间。)
tic = time.time()
和toc = time.time()
,那么print toc-tic, 'sec Elapsed'
正如下面的人们所说的那样,timeit
它更强大。