如何用Python的timeit测量代码段性能?

247 投票
9 回答
358423 浏览
提问于 2025-04-15 22:54

我有一个Python脚本,运行得很好,但我需要记录它的执行时间。我在网上查了,发现可以用timeit这个工具,但我好像没法让它正常工作。

我的Python脚本长这样:

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\n" % r        
    ibm_db.execute(query_stmt)
 query_stmt = ibm_db.prepare(conn, update)

myfile.close()
ibm_db.close(conn)

我需要的是执行这个查询所花的时间,并把它写入文件results_update.txt。这样做的目的是为了测试我的数据库更新语句,看看在不同的索引和调优机制下表现如何。

9 个回答

45

首先,这段代码有问题:你执行了100个连接(只关注最后一个),然后在第一次执行时,你传入了一个局部变量 query_stmt,而这个变量是在执行调用之后才初始化的。

首先,先把代码修正过来,不用担心时间的问题:也就是说,写一个函数来建立连接,进行100次、500次或者其他次数的更新,然后关闭连接。等你的代码能正常工作后,再考虑用 timeit 来测试它的执行时间!

具体来说,如果你想要计时的函数是一个不带参数的函数,叫做 foobar,你可以使用 timeit.timeit(2.6版本或更高,2.5及之前的版本会复杂一些):

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

从3.5版本开始,globals 参数让你可以很方便地用 timeit 来测试带参数的函数:

timeit.timeit('foobar(x,y)', number=1000, globals = globals())

最好指定运行的次数,因为默认是一百万次,这对你的使用场景来说可能太多了(可能会花很多时间在这段代码上;-)。

73

如果你正在分析你的代码性能,并且可以使用IPython,那么它有一个很方便的功能叫做 %timeit

%%timeit 是用在代码单元格上的。

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
402

你可以在想要测量时间的代码块前后使用 time.time()time.clock()

import time

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

total = t1-t0

这种方法没有 timeit 那么精确(因为它不会对多次运行的结果取平均),但使用起来很简单。

time.time()(在Windows和Linux上)和 time.clock()(在Linux上)对于快速的函数来说不够精确(你可能会得到总时间为0)。在这种情况下,或者如果你想对多次运行的时间进行平均,你需要手动多次调用这个函数(就像你在示例代码中已经做的那样,而 timeit 会在你设置它的 number 参数时自动处理这个)。

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.clock() 而不是 time.time()

撰写回答