python中函数的准确计时

Ati*_*son 62 python testing time profiling

我正在使用Windows上的python进行编程,并希望准确地测量函数运行所需的时间.我编写了一个函数"time_it",它接受另一个函数,运行它,并返回运行所花费的时间.

def time_it(f, *args):
    start = time.clock()
    f(*args)
    return (time.clock() - start)*1000
Run Code Online (Sandbox Code Playgroud)

我称之为1000次,并对结果取平均值.(最后的1000常量是以毫秒为单位给出答案.)

这个功能似乎有效,但我有这种唠叨的感觉,我做错了,通过这样做,我使用的时间超过了它运行时实际使用的功能.

是否有更标准或可接受的方式来做到这一点?

当我更改我的测试函数以调用打印以使其花费更长时间时,我的time_it函数返回平均2.5 ms,而cProfile.run('f()')返回并平均为7.0 ms.我认为我的功能会高估时间,如果有的话,这里发生了什么?

还有一点需要注意,它是我所关心的功能相对时间,而不是绝对时间,因为这显然会因硬件和其他因素而异.

Ale*_*lli 69

使用Python标准库中的timeit模块.

基本用法:

from timeit import Timer

# first argument is the code to be run, the second "setup" argument is only run once,
# and it not included in the execution time.
t = Timer("""x.index(123)""", setup="""x = range(1000)""")

print t.timeit() # prints float, for example 5.8254
# ..or..
print t.timeit(1000) # repeat 1000 times instead of the default 1million
Run Code Online (Sandbox Code Playgroud)

  • 我想用不同的争论来调用我的函数,但是当我用不同的争论调用t = timeit.Timer("f()","from ___main___ import f")并再次运行t.timeit(10000)时,我得到了虽然不同的争论应该导致非常不同的运行时间,但结果相同. (2认同)

Dan*_*Lew 37

我建议您查看内置的Python分析器(profile或者cProfile,根据您的需要),而不是编写自己的分析代码:http://docs.python.org/library/profile.html


vdr*_*mrt 30

您可以像这样创建一个"timeme"装饰器

import time                                                

def timeme(method):
    def wrapper(*args, **kw):
        startTime = int(round(time.time() * 1000))
        result = method(*args, **kw)
        endTime = int(round(time.time() * 1000))

        print(endTime - startTime,'ms')
        return result

    return wrapper

@timeme
def func1(a,b,c = 'c',sleep = 1):
    time.sleep(sleep)
    print(a,b,c)

func1('a','b','c',0)
func1('a','b','c',0.5)
func1('a','b','c',0.6)
func1('a','b','c',1)
Run Code Online (Sandbox Code Playgroud)

  • 这非常适用于非递归函数.对于递归函数,它返回函数每次迭代的时间. (7认同)

S.L*_*ott 23

此代码非常不准确

total= 0
for i in range(1000):
    start= time.clock()
    function()
    end= time.clock()
    total += end-start
time= total/1000
Run Code Online (Sandbox Code Playgroud)

此代码不太准确

start= time.clock()
for i in range(1000):
    function()
end= time.clock()
time= (end-start)/1000
Run Code Online (Sandbox Code Playgroud)

如果函数的运行时间接近时钟精度,则非常不准确会受到测量偏差的影响.大多数测量时间仅仅是0到几个时钟周期之间的随机数.

根据您的系统工作负载,您从单个函数中观察到的"时间"可能完全是OS调度和其他无法控制的开销的工件.

第二个版本(不太准确)具有较少的测量偏差.如果您的功能非常快,您可能需要运行10,000次以阻止操作系统调度和其他开销.

当然,两者都是非常误导的.程序的运行时间 - 作为一个整体 - 不是函数运行时间的总和.您只能使用这些数字进行相对比较.它们不是传达意义的绝对测量.

  • @pixelgrease,/ 1000因为函数执行了1000次.所以`time`是执行一次函数所需的平均时间. (8认同)
  • 为什么/ 1000?time.clock()方法返回秒作为浮点值.如果你期望它返回毫秒,这将是有意义的,但除以1000转换为千秒,这是我以前从未见过的单位. (3认同)

kir*_*off 14

如果你想计算一个python方法,即使你测量的块可能会抛出,一个好方法是使用with语句.将某个Timer类定义为

import time

class Timer:    
    def __enter__(self):
        self.start = time.clock()
        return self

    def __exit__(self, *args):
        self.end = time.clock()
        self.interval = self.end - self.start
Run Code Online (Sandbox Code Playgroud)

然后你可能想要计时可能抛出的连接方法.使用

import httplib

with Timer() as t:
    conn = httplib.HTTPConnection('google.com')
    conn.request('GET', '/')

print('Request took %.03f sec.' % t.interval)
Run Code Online (Sandbox Code Playgroud)

__exit()__即使连接请求发生,也会调用方法.更准确地说,你可以使用它try finally来查看结果,以防它被抛出

try:
    with Timer() as t:
        conn = httplib.HTTPConnection('google.com')
        conn.request('GET', '/')
finally:
    print('Request took %.03f sec.' % t.interval)
Run Code Online (Sandbox Code Playgroud)

更多细节在这里.


Jas*_*rgh 7

这个更整洁

from contextlib import contextmanager

import time
@contextmanager
def timeblock(label):
    start = time.clock()
    try:
        yield
    finally:
        end = time.clock()
        print ('{} : {}'.format(label, end - start))



with timeblock("just a test"):
            print "yippee"
Run Code Online (Sandbox Code Playgroud)


Bin*_*sim 5

类似于@AlexMartelli的答案

import timeit
timeit.timeit(fun, number=10000)
Run Code Online (Sandbox Code Playgroud)

可以做到这一点。