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()) 

由于这是通过推动堆栈的开始时间来工作的,所以它可以正确地工作在多层次的tictoc 。 它还允许更改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不打印经过的时间,但返回它。)