212

我有一个可以正常工作的 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。目的是使用不同的索引和调整机制测试我的数据库的更新语句。

4

9 回答 9

349

您可以使用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.time().

于 2010-05-19T14:32:35.007 回答
54

如果您正在分析您的代码并且可以使用 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
于 2014-03-02T23:26:59.503 回答
39

除了时间之外,您显示的这段代码根本不正确:您执行 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())

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

于 2010-05-19T14:33:06.043 回答
14

专注于一件特定的事情。磁盘 I/O 很慢,所以如果您要调整的只是数据库查询,我会将其排除在测试之外。

如果您需要为数据库执行计时,请寻找数据库工具,例如询问查询计划,并注意性能不仅会因确切的查询和您拥有的索引而异,而且会因数据负载(有多少数据您已存储)。

也就是说,您可以简单地将代码放入函数中并使用以下命令运行该函数timeit.timeit()

def function_to_repeat():
    # ...

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

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

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

def function_to_repeat(var1, var2):
    # ...

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

将获取 globals function_to_repeatvar1var2从您的脚本中获取并将它们传递给每次重复的函数。

于 2016-03-26T16:00:46.667 回答
5

这是史蒂文答案的简单包装。此功能不会重复运行/平均,只是让您不必在任何地方重复计时代码:)

'''function which prints the wall time it takes to execute the given command'''
def time_func(func, *args): #*args can take 0 or more 
  import time
  start_time = time.time()
  func(*args)
  end_time = time.time()
  print("it took this long to run: {}".format(end_time-start_time))
于 2019-05-22T13:33:56.480 回答
2

我看到这个问题已经得到解答,但仍然想加我的 2 美分。

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

该脚本也可在此处作为 github gist 获得。

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

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();"\n\n
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")
于 2015-12-19T11:07:44.970 回答
1

测试套件不会尝试使用导入timeit的,因此很难判断其意图是什么。尽管如此,这是一个规范的答案,所以一个完整的例子timeit似乎是有序的,详细说明了Martijn 的答案

文档timeit提供了许多值得一试的示例和标志。命令行的基本用法是:

$ python -mtimeit "all(True for _ in range(1000))"
2000 loops, best of 5: 161 usec per loop
$ python -mtimeit "all([True for _ in range(1000)])"
2000 loops, best of 5: 116 usec per loop

运行-h以查看所有选项。Python MOTW有一个很棒的部分timeit展示了如何通过命令行的导入和多行代码字符串运行模块。

在脚本形式中,我通常这样使用它:

import argparse
import copy
import dis
import inspect
import random
import sys
import timeit

def test_slice(L):
    L[:]

def test_copy(L):
    L.copy()

def test_deepcopy(L):
    copy.deepcopy(L)

if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument("--n", type=int, default=10 ** 5)
    parser.add_argument("--trials", type=int, default=100)
    parser.add_argument("--dis", action="store_true")
    args = parser.parse_args()
    n = args.n
    trials = args.trials
    namespace = dict(L = random.sample(range(n), k=n))
    funcs_to_test = [x for x in locals().values() 
                     if callable(x) and x.__module__ == __name__]
    print(f"{'-' * 30}\nn = {n}, {trials} trials\n{'-' * 30}\n")

    for func in funcs_to_test:
        fname = func.__name__
        fargs = ", ".join(inspect.signature(func).parameters)
        stmt = f"{fname}({fargs})"
        setup = f"from __main__ import {fname}"
        time = timeit.timeit(stmt, setup, number=trials, globals=namespace)
        print(inspect.getsource(globals().get(fname)))

        if args.dis:
            dis.dis(globals().get(fname))

        print(f"time (s) => {time}\n{'-' * 30}\n")

你可以很容易地放入你需要的函数和参数。使用不纯函数时要小心并注意状态。

样本输出:

$ python benchmark.py --n 10000
------------------------------
n = 10000, 100 trials
------------------------------

def test_slice(L):
    L[:]

time (s) => 0.015502399999999972
------------------------------

def test_copy(L):
    L.copy()

time (s) => 0.01651419999999998
------------------------------

def test_deepcopy(L):
    copy.deepcopy(L)

time (s) => 2.136012
------------------------------
于 2020-07-12T18:50:20.840 回答
1

另一个简单的 timeit 示例:

def your_function_to_test():
   # do some stuff...

time_to_run_100_times = timeit.timeit(lambda: your_function_to_test, number=100)
于 2020-07-23T07:48:31.460 回答
1

以下是如何使用 对函数计时的示例timeit

import timeit

def time_this():
    return [str(i) for i in range(5000)]

timeit.timeit(time_this, number=1000)

这将返回执行time_this()函数 1000 次所需的时间(以秒为单位)。

于 2021-02-21T20:41:56.360 回答