标签归档:callback

Python时间测量功能

问题:Python时间测量功能

我想创建一个python函数来测试在每个函数中花费的时间,并用时间显示其名称,我该如何打印函数名称,如果还有另一种方法,请告诉我

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

I want to create a python function to test the time spent in each function and print its name with its time, how i can print the function name and if there is another way to do so please tell me

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

回答 0

首先,我强烈建议使用探查器或至少使用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, **kwargs):
        time1 = time.time()
        ret = f(*args, **kwargs)
        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中)或f.__name__ 在Python 3中。

First and foremost, I highly suggest using a profiler or atleast use timeit.

However if you wanted to write your own timing method strictly to learn, here is somewhere to get started using a decorator.

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

And the usage is very simple, just use the @timing decorator:

@timing
def do_work():
  #code

Python 3:

def timing(f):
    def wrap(*args, **kwargs):
        time1 = time.time()
        ret = f(*args, **kwargs)
        time2 = time.time()
        print('{:s} function took {:.3f} ms'.format(f.__name__, (time2-time1)*1000.0))

        return ret
    return wrap

Note I’m calling f.func_name to get the function name as a string(in Python 2), or f.__name__ in Python 3.


回答 1

在玩完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)

上下文管理器方法

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)

看起来不太好…如果您使用的是没有nonlocal关键字的Python 2,该怎么办?

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

images = get_images()
with timeit_context('foobar'):
    bigImage = ImagePacker.pack(images, width=4096)
drawer.draw(bigImage)

After playing with the timeit module, I don’t like its interface, which is not so elegant compared to the following two method.

The following code is in Python 3.

The decorator method

This is almost the same with @Mike’s method. Here I add kwargs and functools wrap to make it better.

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)

The context manager method

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

For example, you can use it like:

with timeit_context('My profiling code'):
    mike = Person()
    mike.think()

And the code within the with block will be timed.

Conclusion

Using the first method, you can eaily comment out the decorator to get the normal code. However, it can only time a function. If you have some part of code that you don’t what to make it a function, then you can choose the second method.

For example, now you have

images = get_images()
bigImage = ImagePacker.pack(images, width=4096)
drawer.draw(bigImage)

Now you want to time the bigImage = ... line. If you change it to a function, it will be:

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

Looks not so great…What if you are in Python 2, which has no nonlocal keyword.

Instead, using the second method fits here very well:

images = get_images()
with timeit_context('foobar'):
    bigImage = ImagePacker.pack(images, width=4096)
drawer.draw(bigImage)

回答 2

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

import timeit
timeit.timeit(a, number=1)

也可以向函数发送参数。您需要做的就是使用装饰器包装功能。此处有更多说明: http //www.pythoncentral.io/time-a-python-function/

您可能对编写自己的时序语句感兴趣的唯一情况是,您只想运行一个函数并且还希望获得其返回值。

使用该timeit模块的优势 在于,它使您可以重复执行次数。这可能是必要的,因为其他过程可能会干扰您的计时精度。因此,您应该多次运行它并查看最小值。

I don’t see what the problem with the timeit module is. This is probably the simplest way to do it.

import timeit
timeit.timeit(a, number=1)

Its also possible to send arguments to the functions. All you need is to wrap your function up using decorators. More explanation here: http://www.pythoncentral.io/time-a-python-function/

The only case where you might be interested in writing your own timing statements is if you want to run a function only once and are also want to obtain its return value.

The advantage of using the timeit module is that it lets you repeat the number of executions. This might be necessary because other processes might interfere with your timing accuracy. So, you should run it multiple times and look at the lowest value.


回答 3

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)

Timeit has two big flaws: it doesn’t return the return value of the function, and it uses eval, which requires passing in extra setup code for imports. This solves both problems simply and elegantly:

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

有一个简单的计时工具。https://github.com/RalphMao/PyTimer

它可以像装饰器一样工作:

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

输出:

========Timing Summary of Default Timer========
block2:0.065062
block1:0.032529
========Timing Summary of Default Timer========
block2:0.065838
block1:0.032891

希望对你有帮助

There is an easy tool for timing. https://github.com/RalphMao/PyTimer

It can work like a decorator:

from pytimer import Timer
@Timer(average=False)      
def matmul(a,b, times=100):
    for i in range(times):
        np.dot(a,b)        

Output:

matmul:0.368434
matmul:2.839355

It can also work like a plug-in timer with namespace control(helpful if you are inserting it to a function which has a lot of codes and may be called anywhere else).

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

Output:

========Timing Summary of Default Timer========
block2:0.065062
block1:0.032529
========Timing Summary of Default Timer========
block2:0.065838
block1:0.032891

Hope it will help


回答 5

使用装饰器Python库的Decorator方法:

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

请参阅我的博客上的文章:

在mobilepro.pl博客上发布

我在Google Plus上的信息

Decorator method using decorator Python library:

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

See post on my Blog:

post on mobilepro.pl Blog

my post on Google Plus


回答 6

我的做法:

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)在块之后立即设置变量。

然后你得到了答案。

My way of doing it:

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."

Set a variable as start = time() before execute the function/loops, and printTime(start) right after the block.

and you got the answer.