如何使用Pythons timeit计算代码段以测试性能?

How can I time a code segment for testing performance with Pythons timeit?

我有一个可以正常工作的Python脚本,但我需要编写执行时间。我在google上搜索到我应该使用timeit,但我似乎无法让它工作。

我的python脚本如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import sys
import getopt
import timeit
import random
import os
import re
import ibm_db
import time
from string import maketrans
myfile = open("results_update.txt","a")

for r in range(100):
    rannumber = random.randint(0, 100)

    update ="update TABLE set val = %i where MyCount >= '2010' and MyCount < '2012' and number = '250'" % rannumber
    #print rannumber

    conn = ibm_db.pconnect("dsn=myDB","usrname","secretPWD")

for r in range(5):
    print"Run %s
"
% r        
    ibm_db.execute(query_stmt)
 query_stmt = ibm_db.prepare(conn, update)

myfile.close()
ibm_db.close(conn)

我需要的是执行查询并将其写入文件results_update.txt所需的时间。目的是用不同的索引和调优机制测试数据库的更新语句。


您可以在要计时的块之前和之后使用time.time()time.clock()

1
2
3
4
5
6
7
import time

t0 = time.time()
code_block
t1 = time.time()

total = t1-t0

这种方法不如timeit精确(它不平均几次运行),但很简单。

time.time()(在Windows和Linux中)和time.clock()(在Linux中)对于快速函数来说不够精确(您得到的总数为0)。在这种情况下,或者如果要平均多次运行所用的时间,则必须多次手动调用该函数(我认为您已经在示例代码和时间中这样做了,当您设置其数字参数时,它会自动调用)。

1
2
3
4
5
6
7
8
9
10
11
import time

def myfast():
   code

n = 10000
t0 = time.time()
for i in range(n): myfast()
t1 = time.time()

total_n = t1-t0

在windows中,如corey在评论中所说,time.clock()的精度要高得多(微秒而不是秒),它比time.time()更受欢迎。


如果您正在分析代码并可以使用ipython,那么它具有魔力函数%timeit

%%timeit作用于细胞。

1
2
3
4
5
6
7
8
In [2]: %timeit cos(3.14)
10000000 loops, best of 3: 160 ns per loop

In [3]: %%timeit
   ...: cos(3.14)
   ...: x = 2 + 3
   ...:
10000000 loops, best of 3: 196 ns per loop


除了时间之外,您所显示的代码是完全不正确的:您执行100个连接(完全忽略最后一个连接以外的所有连接),然后当您执行第一个执行调用时,将传递给它一个局部变量query_stmt,该变量只有在执行调用之后才能初始化。

首先,让您的代码正确无误,而不必担心时间问题:即,一个建立或接收连接并在该连接上执行100或500或任何数量的更新的函数,然后关闭该连接。一旦您的代码工作正常,您就可以正确地考虑在上面使用timeit

具体来说,如果要计时的函数是一个参数,而不是一个名为foobar的参数,则可以使用timeit.timeit(2.6或更高版本——在2.5及之前版本中更复杂):

1
timeit.timeit('foobar()', number=1000)

您最好指定运行次数,因为对于您的用例,默认值一百万可能很高(这会导致在代码中花费大量时间;-)。


专注于一件具体的事情。磁盘I/O速度很慢,所以如果您要调整的只是数据库查询,那么我将把它从测试中去掉。

如果您需要对数据库的执行进行计时,那么可以寻找数据库工具,比如询问查询计划,并注意性能不仅会随着准确的查询和所拥有的索引而变化,还会随着数据负载(存储了多少数据)而变化。

也就是说,您只需将代码放入一个函数中,并使用timeit.timeit()运行该函数即可:

1
2
3
4
def function_to_repeat():
    # ...

duration = timeit.timeit(function_to_repeat, number=1000)

这将禁用垃圾收集,重复调用function_to_repeat()函数,并使用timeit.default_timer()计算这些调用的总持续时间,这是您特定平台最准确的可用时钟。

您应该将设置代码移出重复的函数;例如,您应该首先连接到数据库,然后只对查询计时。使用setup参数导入或创建这些依赖项,并将它们传递到函数中:

1
2
3
4
5
6
7
def function_to_repeat(var1, var2):
    # ...

duration = timeit.timeit(
    'function_to_repeat(var1, var2)',
    'from __main__ import function_to_repeat, var1, var2',
    number=1000)

将从脚本中获取全局的function_to_repeatvar1var2,并将它们传递给函数每个重复。


我看到问题已经被回答了,但还是想加上我的2分。

我也遇到过类似的情况,在这种情况下,我必须测试几种方法的执行时间,然后编写一个小脚本,在其中编写的所有函数上调用timeit。

该脚本也可以在这里作为Github Gist使用。

希望它能帮助你和其他人。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
from random import random
import types

def list_without_comprehension():
    l = []
    for i in xrange(1000):
        l.append(int(random()*100 % 100))
    return l

def list_with_comprehension():
    # 1K random numbers between 0 to 100
    l = [int(random()*100 % 100) for _ in xrange(1000)]
    return l


# operations on list_without_comprehension
def sort_list_without_comprehension():
    list_without_comprehension().sort()

def reverse_sort_list_without_comprehension():
    list_without_comprehension().sort(reverse=True)

def sorted_list_without_comprehension():
    sorted(list_without_comprehension())


# operations on list_with_comprehension
def sort_list_with_comprehension():
    list_with_comprehension().sort()

def reverse_sort_list_with_comprehension():
    list_with_comprehension().sort(reverse=True)

def sorted_list_with_comprehension():
    sorted(list_with_comprehension())


def main():
    objs = globals()
    funcs = []
    f = open("timeit_demo.sh","w+")

    for objname in objs:
        if objname != 'main' and type(objs[objname]) == types.FunctionType:
            funcs.append(objname)
    funcs.sort()
    for func in funcs:
        f.write('''echo"Timing: %(funcname)s"
python -m timeit"import timeit_demo; timeit_demo.%(funcname)s();"


echo"------------------------------------------------------------"
'''
% dict(
                funcname = func,
                )
            )

    f.close()

if __name__ =="__main__":
    main()

    from os import system

    #Works only for *nix platforms
    system("/bin/bash timeit_demo.sh")

    #un-comment below for windows
    #system("cmd timeit_demo.sh")