Python时间测量功能

Waz*_*ery 116 python time callback

我想创建一个python函数来测试每个函数花费的时间,并用它的时间打印它的名字,如何打印函数名称,如果还有其他方法,请告诉我

def measureTime(a):
    start = time.clock() 
    a()
    elapsed = time.clock()
    elapsed = elapsed - start
    print "Time spent in (function name) is: ", elapsed
Run Code Online (Sandbox Code Playgroud)

Mik*_*wis 232

首先,我强烈建议使用分析器或至少使用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
Run Code Online (Sandbox Code Playgroud)

用法很简单,只需使用@timing装饰器:

@timing
def do_work():
  #code
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

注意我正在调用f.func_name将函数名称作为字符串(在Python 2中)或f.__name__ 在Python 3中.

  • 正是我想要的:) ...但你们说服我使用python profiler (4认同)
  • 看起来这假设time.time()报告自纪元以来的微秒时间?文档说它以秒为单位报告时间https://docs.python.org/2/library/time.html#time.time. (3认同)

Ray*_*Ray 45

在玩timeit模块之后,我不喜欢它的界面,与以下两种方法相比,它不是那么优雅.

以下代码在Python 3中.

装饰方法

这与@Mike的方法几乎相同.在这里,我添加kwargsfunctools包装以使其更好.

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)
Run Code Online (Sandbox Code Playgroud)

上下文管理器方法

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)))
Run Code Online (Sandbox Code Playgroud)

例如,您可以使用它:

with timeit_context('My profiling code'):
    mike = Person()
    mike.think()
Run Code Online (Sandbox Code Playgroud)

并且with块内的代码将被定时.

结论

使用第一种方法,您可以每天注释掉装饰器以获取正常代码.但是,它只能计时功能.如果你有一部分代码不能使它成为一个函数,那么你可以选择第二种方法.

例如,现在你有

images = get_images()
bigImage = ImagePacker.pack(images, width=4096)
drawer.draw(bigImage)
Run Code Online (Sandbox Code Playgroud)

现在你想要bigImage = ...排队.如果将其更改为函数,则为:

images = get_images()
bitImage = None
@timeit
def foobar():
    nonlocal bigImage
    bigImage = ImagePacker.pack(images, width=4096)
drawer.draw(bigImage)
Run Code Online (Sandbox Code Playgroud)

看起来不那么好......如果您使用的是Python 2,它没有nonlocal关键字.

相反,使用第二种方法非常适合:

images = get_images()
with timeit_context('foobar'):
    bigImage = ImagePacker.pack(images, width=4096)
drawer.draw(bigImage)
Run Code Online (Sandbox Code Playgroud)

  • 需要`import functools` (2认同)
  • 请注意,您的装饰器丢失了原始函数的返回值 (2认同)

Pha*_*ani 11

我没有看到timeit模块的问题是什么.这可能是最简单的方法.

import timeit
timeit.timeit(a, number=1)
Run Code Online (Sandbox Code Playgroud)

它也可以向函数发送参数.您所需要的只是使用装饰器包装您的功能.这里有更多解释:http://www.pythoncentral.io/time-a-python-function/

您可能有兴趣编写自己的计时语句的唯一情况是,如果您只想运行一次函数,并且还想获取其返回值.

使用该timeit模块的优点 是它可以让您重复执行的次数.这可能是必要的,因为其他过程可能会影响您的计时准确性.因此,您应该多次运行它并查看最低值.

  • 使用包装器和装饰器向函数发送参数?为什么不`timeit.timeit(lambda:func(a,b,c),number = 1)`?我在对终端中的假设解决方案进行测试时使用它. (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)
Run Code Online (Sandbox Code Playgroud)