tic,toc在Python中起着模拟的作用
在Python中,什么是MATLAB tic和toc函数的最佳模拟( http://www.mathworks.com/help/techdoc/ref/tic.html )?
除了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)
它可以用作上下文pipe理器:
with Timer('foo_stuff'): # do some foo # do some stuff
有时候我发现这个技术比timeit
更方便 – 这一切都取决于你想要测量什么。
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()
当我从Matlab迁移到python时,我有同样的问题。 在这个线程的帮助下,我能够构build一个精确的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)
而已! 现在我们已经准备好像在Matlab中一样完全使用tic()
和toc()
。 例如
tic() time.sleep(5) toc() # returns "Elapsed time: 5.00 seconds."
实际上,这比内置的Matlab函数更通用。 在这里,您可以创build另一个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...
我希望这是有帮助的。
通常,IPython的%time
, %timeit
, %prun
和%lprun
(如果安装了line_profiler
)满足我的分析需求。 然而,当我尝试剖析交互式驱动的计算时(即通过用户在GUI中的鼠标移动),出现了一个类似tic-toc
的function的用例。 我觉得像垃圾邮件中的垃圾邮件和交互式testing是最快揭示瓶颈的方法。 我和Eli Bendersky的Timer
类一起工作,但并不满意,因为它需要我改变我的代码的缩进,这在一些编辑器中是不方便的,并且会使版本控制系统混淆。 而且,可能需要测量不同function中的点之间的时间,这对于with
语句不起作用。 在尝试了很多Python智能之后,下面是我find的最简单的解决scheme:
from time import time _tstart_stack = [] def tic(): _tstart_stack.append(time()) def toc(fmt="Elapsed: %ss"): print fmt % (time() - _tstart_stack.pop())
由于这是通过推动堆栈的开始时间来工作的,所以它可以正确地工作在多层次的tic
和toc
。 它还允许更改toc
语句的格式string以显示其他信息,我喜欢Eli的Timer
类。
出于某种原因,我担心纯Python实现的开销,所以我也testing了一个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微秒执行的代码块。 在此之下,需要像时间这样的平均策略来获得忠实的测量结果。
我刚刚创build了一个模块[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()
我希望它有帮助。
看看timeit
模块。 这不是等同的,但如果你想要的代码是在一个函数内,你可以很容易地使用它。
我改变了@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+xT)/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
这也可以使用包装来完成。 保持时间的一般方法。
本示例代码中的包装函数包装了所有函数,并显示了执行该函数所需的时间:
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()
在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不打印经过的时间,但返回它。)