2009-05-20 51 views
55

我正在用python编程windows,并希望准确测量函数运行所需的时间。我写了一个函数“time_it”,它接受另一个函数,运行它并返回运行所需的时间。python中函数的准确定时

def time_it(f, *args): 
    start = time.clock() 
    f(*args) 
    return (time.clock() - start)*1000 

我把这1000次称为平均值。 (最后的1000常数以毫秒为单位给出答案)

此功能似乎有效,但我有这种唠叨的感觉,我做错了什么,而且通过这样做我正在使用比运行时实际使用的更多时间。

有没有一个更标准或接受的方式来做到这一点?

当我改变我的测试函数来调用打印,以便它需要更长时间时,我的time_it函数返回平均2.5毫秒,而cProfile.run('f()')返回并平均为7.0毫秒。我想我的功能会高估时间,如果有的话,这里发生了什么?

另外需要注意的是,我关心的是相互比较的功能相对时间,而不是绝对时间,因为硬件和其他因素会明显改变。

回答

33

而不是写自己的监测代码的,我建议你检查出内置Python分析器(profilecProfile,根据您的需要):http://docs.python.org/library/profile.html

+0

忽略我 - 该字符串不是函数名称,它是一个eval'd代码块。所以你可以用它来快速计时。这是正确的答案。而在其他消息中 - “不是”比“!=”快得多 - 但可能有其他影响。 – 2012-06-11 10:20:09

+1

关于该切线 - 使用之前“不是”的任何聪明 - 记住这一点 - http://stackoverflow.com/questions/1392433/python-why-is-hello-is-hello – 2012-06-11 10:41:43

65

使用从Python标准库。

基本用法:

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 
+2

我想我的功能被称为不同的争论,但是当我用不同的论证调用t = timeit.Timer(“f()”,“from ___main___ import f”)并再次运行t.timeit(10000)时,我得到了相同的结果,尽管不同的论证应该导致运行时间非常不同。 – 2009-05-20 20:47:39

20

此代码是非常不准确的

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

此代码是不太准确的测量偏差

start= time.clock() 
for i in range(1000): 
    function() 
end= time.clock() 
time= (end-start)/1000 

非常不准确遭受如果运行时的功能接近于时钟的精度。大部分测量时间仅仅是0到几个时钟周期之间的随机数。

根据您的系统工作负载,您从单个函数观察到的“时间”可能完全是操作系统调度和其他不可控制的开销的人为因素。

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

当然,这两者都是非常具有误导性的。程序的运行时间 - 整体而言 - 不是函数运行时间的总和。您只能使用数字进行相对比较。它们不是绝对的量度,传达了很多意义。

+1

为什么/ 1000? time.clock()方法返回秒数作为浮点值。如果你期望它返回毫秒,这是有道理的,但是除以1000转换为千位,这是我以前从未见过的单位。 – pixelgrease 2014-08-15 20:25:19

+0

@pixelgrease milli/1000 =微,而不是公斤:) – stenci 2014-10-22 20:06:17

13

如果您想要测量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 

那么你可能需要的时间可能会抛出一个连接方法。使用

import httplib 

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

print('Request took %.03f sec.' % t.interval) 

__exit()__即使连接请求流逝,方法也会被调用。更准确地说,你必须使用tryfinally看到情况下,它抛出的结果是,与

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

More details here.

23

您可以创建一个像这样

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) 
6
一个“timeme”装饰

这是整洁的

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

类似于@ AlexMartelli的回答

import timeit 
timeit.timeit(fun, number=10000) 

可以做到这一点。