问题:Matlab的tic和toc函数的Python等效项是什么?
回答 0
除了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
它更方便-取决于您要测量的内容。
Apart from timeit
which ThiefMaster mentioned, a simple way to do it is just (after importing time
):
t = time.time()
# do stuff
elapsed = time.time() - t
I have a helper class I like to use:
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))
It can be used as a context manager:
with Timer('foo_stuff'):
# do some foo
# do some stuff
Sometimes I find this technique more convenient than timeit
– it all depends on what you want to measure.
回答 1
从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...
我希望这会有所帮助。
I had the same question when I migrated to python from Matlab. With the help of this thread I was able to construct an exact analog of the Matlab tic()
and toc()
functions. Simply insert the following code at the top of your 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)
That’s it! Now we are ready to fully use tic()
and toc()
just as in Matlab. For example
tic()
time.sleep(5)
toc() # returns "Elapsed time: 5.00 seconds."
Actually, this is more versatile than the built-in Matlab functions. Here, you could create another instance of the TicTocGenerator
to keep track of multiple operations, or just to time things differently. For instance, while timing a script, we can now time each piece of the script seperately, as well as the entire script. (I will provide a concrete example)
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)
Now you should be able to time two separate things: In the following example, we time the total script and parts of a script separately.
tic()
time.sleep(5)
tic2()
time.sleep(3)
toc2() # returns "Elapsed time 2: 5.00 seconds."
toc() # returns "Elapsed time: 8.00 seconds."
Actually, you do not even need to use tic()
each time. If you have a series of commands that you want to time, then you can write
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...
I hope that this is helpful.
回答 2
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()
The absolute best analog of tic and toc would be to simply define them in 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"
Then you can use them as:
tic()
# do stuff
toc()
回答 3
通常情况下,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的平均策略才能获得忠实的度量。
Usually, IPython’s %time
, %timeit
, %prun
and %lprun
(if one has line_profiler
installed) satisfy my profiling needs quite well. However, a use case for tic-toc
-like functionality arose when I tried to profile calculations that were interactively driven, i.e., by the user’s mouse motion in a GUI. I felt like spamming tic
s and toc
s in the sources while testing interactively would be the fastest way to reveal the bottlenecks. I went with Eli Bendersky’s Timer
class, but wasn’t fully happy, since it required me to change the indentation of my code, which can be inconvenient in some editors and confuses the version control system. Moreover, there may be the need to measure the time between points in different functions, which wouldn’t work with the with
statement. After trying lots of Python cleverness, here is the simple solution that I found worked best:
from time import time
_tstart_stack = []
def tic():
_tstart_stack.append(time())
def toc(fmt="Elapsed: %s s"):
print fmt % (time() - _tstart_stack.pop())
Since this works by pushing the starting times on a stack, it will work correctly for multiple levels of tic
s and toc
s. It also allows one to change the format string of the toc
statement to display additional information, which I liked about Eli’s Timer
class.
For some reason I got concerned with the overhead of a pure Python implementation, so I tested a C extension module as well:
#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);
}
This is for MacOSX, and I have omitted code to check if lvl
is out of bounds for brevity. While tictoc.res()
yields a resolution of about 50 nanoseconds on my system, I found that the jitter of measuring any Python statement is easily in the microsecond range (and much more when used from IPython). At this point, the overhead of the Python implementation becomes negligible, so that it can be used with the same confidence as the C implementation.
I found that the usefulness of the tic-toc
-approach is practically limited to code blocks that take more than 10 microseconds to execute. Below that, averaging strategies like in timeit
are required to get a faithful measurement.
回答 4
您可以使用tic
和toc
从ttictoc
。用安装
pip install ttictoc
然后按照以下步骤将它们导入您的脚本中
from ttictoc import tic,toc
tic()
# Some code
print(toc())
You can use tic
and toc
from ttictoc
. Install it with
pip install ttictoc
And just import them in your script as follow
from ttictoc import tic,toc
tic()
# Some code
print(toc())
回答 5
我刚刚创建了一个模块[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()
希望对您有所帮助。
I have just created a module [tictoc.py] for achieving nested tic tocs, which is what Matlab does.
from time import time
tics = []
def tic():
tics.append(time())
def toc():
if len(tics)==0:
return None
else:
return time()-tics.pop()
And it works this way:
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()
I hope it helps.
回答 6
看一下timeit
模块。它不是真正等效的,但是如果您要计时的代码在函数内部,则可以轻松使用它。
Have a look at the timeit
module.
It’s not really equivalent but if the code you want to time is inside a function you can easily use it.
回答 7
pip install easy-tictoc
在代码中:
from tictoc import tic, toc
tic()
#Some code
toc()
免责声明:我是这个图书馆的作者。
pip install easy-tictoc
In the code:
from tictoc import tic, toc
tic()
#Some code
toc()
Disclaimer: I’m the author of this library.
回答 8
这也可以使用包装器完成。保留时间的非常通用的方法。
此示例代码中的包装器包装了所有函数,并打印了执行该函数所需的时间:
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()
This can also be done using a wrapper. Very general way of keeping time.
The wrapper in this example code wraps any function and prints the amount of time needed to execute the function:
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()
回答 9
我对@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
I changed @Eli Bendersky’s answer a little bit to use the ctor __init__()
and dtor __del__()
to do the timing, so that it can be used more conveniently without indenting the original code:
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)
To use, simple put Timer(“blahblah”) at the beginning of some local scope. Elapsed time will be printed at the end of the scope:
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
It prints out:
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
回答 10
更新Eli对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)
就像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
Updating Eli’s answer to 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)
Just like Eli’s, it can be used as a context manager:
import time
with Timer('Count'):
for i in range(0,10_000_000):
pass
Output:
[Count] Elapsed: 0.27 seconds
I have also updated it to print the units of time reported (seconds) and trim the number of digits as suggested by Can, and with the option of also appending to a log file. You must import datetime to use the logging feature:
import time
import datetime
with Timer('Count', 'log.txt'):
for i in range(0,10_000_000):
pass
回答 11
基于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不打印经过的时间,而是返回经过的时间。)
Building on Stefan and antonimmo’s answers, I ended up putting
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
in a utils.py
module, and I use it with a
from utils import Tictoc
tic, toc = Tictoc()
This way
- you can simply use
tic()
, toc()
and nest them like in Matlab
- alternatively, you can name them:
tic(1)
, toc(1)
or tic('very-important-block')
, toc('very-important-block')
and timers with different names won’t interfere
- importing them this way prevents interference between modules using it.
(here toc does not print the elapsed time, but returns it.)