我想创建一个python函数来测试每个函数花费的时间,并用它的时间打印它的名字,如何打印函数名称,如果还有其他方法,请告诉我
def measureTime(a):
start = time.clock()
a()
elapsed = time.clock()
elapsed = elapsed - start
print "Time spent in (function name) is: ", elapsed
答案 0 :(得分:225)
首先,我强烈建议您使用profiler或至少使用timeit。
但是如果你想严格编写自己的计时方法来学习,那么这里就是开始使用装饰器的地方。
Python 2:
def timing(f):
def wrap(*args):
time1 = time.time()
ret = f(*args)
time2 = time.time()
print '%s function took %0.3f ms' % (f.func_name, (time2-time1)*1000.0)
return ret
return wrap
使用非常简单,只需使用@timing装饰器:
@timing
def do_work():
#code
Python 3:
def timing(f):
def wrap(*args):
time1 = time.time()
ret = f(*args)
time2 = time.time()
print('{:s} function took {:.3f} ms'.format(f.__name__, (time2-time1)*1000.0))
return ret
return wrap
注意我正在调用f.func_name
将函数名称作为字符串(在Python 2中)或Python 3中的f.__name__
。
答案 1 :(得分:44)
使用timeit
模块后,我不喜欢它的界面,与以下两种方法相比,它不是那么优雅。
以下代码在Python 3中。
这与@Mike的方法几乎相同。在这里,我添加kwargs
和functools
换行以使其更好。
def timeit(func):
@functools.wraps(func)
def newfunc(*args, **kwargs):
startTime = time.time()
func(*args, **kwargs)
elapsedTime = time.time() - startTime
print('function [{}] finished in {} ms'.format(
func.__name__, int(elapsedTime * 1000)))
return newfunc
@timeit
def foobar():
mike = Person()
mike.think(30)
from contextlib import contextmanager
@contextmanager
def timeit_context(name):
startTime = time.time()
yield
elapsedTime = time.time() - startTime
print('[{}] finished in {} ms'.format(name, int(elapsedTime * 1000)))
例如,您可以使用它:
with timeit_context('My profiling code'):
mike = Person()
mike.think()
with
块中的代码将被定时。
使用第一种方法,您可以每天注释掉装饰器以获取正常代码。但是,它只能计时功能。如果你有一部分代码不能使它成为一个函数,那么你可以选择第二种方法。
例如,现在你有了
images = get_images()
bigImage = ImagePacker.pack(images, width=4096)
drawer.draw(bigImage)
现在您想要bigImage = ...
行的时间。如果将其更改为函数,则为:
images = get_images()
bitImage = None
@timeit
def foobar():
nonlocal bigImage
bigImage = ImagePacker.pack(images, width=4096)
drawer.draw(bigImage)
看起来不太好......如果您使用的是Python 2,它没有nonlocal
个关键字。
相反,使用第二种方法非常适合:
images = get_images()
with timeit_context('foobar'):
bigImage = ImagePacker.pack(images, width=4096)
drawer.draw(bigImage)
答案 2 :(得分:11)
我不知道timeit
模块的问题是什么。这可能是最简单的方法。
import timeit
timeit.timeit(a, number=1)
它也可以向函数发送参数。您所需要的只是使用装饰器包装您的功能。这里有更多解释:http://www.pythoncentral.io/time-a-python-function/
您可能有兴趣编写自己的计时语句的唯一情况是,您只想运行一次函数并且还想获得其返回值。
使用timeit
模块的好处是它可以让你repeat执行的次数。这可能是必要的,因为其他过程可能会影响您的计时准确性。因此,您应该多次运行它并查看最低值。
答案 3 :(得分:9)
Timeit有两个很大的缺陷:它不返回函数的返回值,它使用eval,这需要为导入传递额外的设置代码。这简单而优雅地解决了这两个问题:
def timed(f):
start = time.time()
ret = f()
elapsed = time.time() - start
return ret, elapsed
timed(lambda: database.foo.execute('select count(*) from source.apachelog'))
(<sqlalchemy.engine.result.ResultProxy object at 0x7fd6c20fc690>, 4.07547402381897)
答案 4 :(得分:3)
使用装饰器Python库的装饰器方法:
import decorator
@decorator
def timing(func, *args, **kwargs):
'''Function timing wrapper
Example of using:
``@timing()``
'''
fn = '%s.%s' % (func.__module__, func.__name__)
timer = Timer()
with timer:
ret = func(*args, **kwargs)
log.info(u'%s - %0.3f sec' % (fn, timer.duration_in_seconds()))
return ret
请参阅我的博客上的帖子:
答案 5 :(得分:3)
有一个简单的计时工具。 Plunker Example
它可以像装饰器一样工作:
window.onload = function() {
var ctx = document.getElementById("canvas").getContext("2d");
window.myLine = new Chart(ctx, config);
};
输出:
from pytimer import Timer
@Timer(average=False)
def matmul(a,b, times=100):
for i in range(times):
np.dot(a,b)
它也可以像带有名称空间控件的插件计时器一样工作(如果你将它插入到一个有很多代码并且可以在其他任何地方调用的函数,则会很有帮助。)
matmul:0.368434
matmul:2.839355
输出:
timer = Timer()
def any_function():
timer.start()
for i in range(10):
timer.reset()
np.dot(np.ones((100,1000)), np.zeros((1000,500)))
timer.checkpoint('block1')
np.dot(np.ones((100,1000)), np.zeros((1000,500)))
np.dot(np.ones((100,1000)), np.zeros((1000,500)))
timer.checkpoint('block2')
np.dot(np.ones((100,1000)), np.zeros((1000,1000)))
for j in range(20):
np.dot(np.ones((100,1000)), np.zeros((1000,500)))
timer.summary()
for i in range(2):
any_function()
希望它会有所帮助
答案 6 :(得分:2)
我的做法:
from time import time
def printTime(start):
end = time()
duration = end - start
if duration < 60:
return "used: " + str(round(duration, 2)) + "s."
else:
mins = int(duration / 60)
secs = round(duration % 60, 2)
if mins < 60:
return "used: " + str(mins) + "m " + str(secs) + "s."
else:
hours = int(duration / 3600)
mins = mins % 60
return "used: " + str(hours) + "h " + str(mins) + "m " + str(secs) + "s."
在执行函数/循环之前将变量设置为start = time()
,并在块之后立即设置printTime(start)
。
你得到了答案。
答案 7 :(得分:0)
详细介绍@Jonathan Ray,我认为这可以更好地解决问题
import time
import inspect
def timed(f:callable):
start = time.time()
ret = f()
elapsed = 1000*(time.time() - start)
source_code=inspect.getsource(f).strip('\n')
logger.info(source_code+": "+str(elapsed)+" seconds")
return ret
它允许采用常规的代码行,例如a = np.sin(np.pi)
并将其转换为简单的
a = timed(lambda: np.sin(np.pi))
以便将计时打印在记录器上,并且您可以将结果分配给变量,以进行进一步的工作。
我想在python 3.8中可以使用:=
,但我还没有3.8
答案 8 :(得分:0)
下面是一个 Timer 类:
这是你如何使用它:
# Create the timer
timer1 = Timer("a name", log_every=2)
# Use "with"
with timer1:
print("timer1")
# Reuse as a decorator
@timer1
def my_func():
print("my_func")
# Instantiate as a decorator
@Timer("another timer", log_every=1)
def my_func2():
print("my_func2")
my_func()
my_func2()
my_func()
下面是课程
from datetime import datetime
import time, logging, math, threading
class Timer(object):
'''A general timer class. Does not really belong in a judicata file here.'''
def __init__(self, name, log_every = 1):
self.name = name
self.log_every = 1
self.calls = 0
self.total_time = 0
self.total_squared_time = 0
self.min, self.max = None, 0
# Make timer thread-safe by storing the times in thread-local storage.
self._local = threading.local()
self._lock = threading.Lock()
def __enter__(self):
"""Start a new timer"""
self._local.start = datetime.utcnow()
def __exit__(self, exc_type, exc_val, exc_tb):
"""Stop the timer, and report the elapsed time"""
elapsed_time = (datetime.utcnow() - self._local.start).total_seconds()
with self._lock:
self.calls += 1
self.total_time += elapsed_time
if self.min == None or elapsed_time < self.min:
self.min = elapsed_time
if elapsed_time > self.max:
self.max = elapsed_time
self.total_squared_time += elapsed_time * elapsed_time
if self.log_every and (self.calls % self.log_every) == 0:
self.log()
def __call__(self, fn):
'''For use as a decorator.'''
def decorated_timer_function(*args, **kwargs):
with self:
return fn(*args, **kwargs)
return decorated_timer_function
@classmethod
def time_str(cls, secs):
if isinstance(secs, six.string_types):
try:
secs = float(secs)
except:
return "(bad time: %s)"%secs
sign = lambda x: x
if secs < 0:
secs = -secs
sign = lambda x: ("-" + x)
return sign("%d secs"%int(secs) if secs >= 120 else
"%.2f secs" % secs if secs >= 1 else
"%d ms" % int(secs * 1000) if secs >= .01 else
"%.2f ms" % (secs * 1000) if secs >= .0001 else
"%d ns" % int(secs * 1000 * 10000) if secs >= 1e-9 else
"%s" % secs)
def log(self):
if not self.calls:
logging.info("<Timer %s: no calls>"%self.name)
return
avg = 1.0 * self.total_time / self.calls
var = 1.0 * self.total_squared_time / self.calls - avg*avg
std_dev = self.time_str(math.sqrt(var))
total = self.time_str(self.total_time)
min, max, avg = [self.time_str(t) for t in [self.min, self.max, avg]]
logging.info("<Timer %s: N=%s, total=%s, avg=%s, min/max=%s/%s, std=%s>"
%(self.name, self.calls, total, avg, min, max, std_dev))