如何使用Pythons-timeit为测试性能的代码段计时?

如何使用Pythons-timeit为测试性能的代码段计时?,python,testing,timeit,database-tuning,Python,Testing,Timeit,Database Tuning,我有一个python脚本,它可以正常工作,但是我需要编写执行时间。我在谷歌上搜索过我应该用的东西,但我似乎无法让它发挥作用 我的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") fo

我有一个python脚本,它可以正常工作,但是我需要编写执行时间。我在谷歌上搜索过我应该用的东西,但我似乎无法让它发挥作用

我的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)
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")
导入系统 导入getopt 导入时间信息 随机输入 导入操作系统 进口稀土 导入ibm_数据库 导入时间 从字符串导入maketrans myfile=open(“results\u update.txt”、“a”) 对于范围(100)内的r: rannumber=random.randint(01100) update=“update TABLE set val=%i,其中MyCount>='2010'和MyCount<'2012'以及number='250'%rannumber #打印号码 conn=ibm_db.pconnect(“dsn=myDB”、“usrname”、“secretPWD”) 对于范围(5)内的r: 打印“运行%s\n”%r ibm_db.execute(查询stmt) query\u stmt=ibm\u db.prepare(连接,更新) myfile.close() ibm_db.close(康涅狄格州) 我需要的是执行查询并将其写入文件
results\u update.txt
所需的时间。其目的是使用不同的索引和调优机制测试我的数据库的update语句。

您可以在要计时的块之前和之后使用update语句

import time

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

total = t1-t0
此方法不如(它不会平均多次运行)精确,但它很简单

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


在Windows中,正如Corey在评论中所说,
time.clock()
具有更高的精度(微秒而不是秒),并且优于
time.time()

除了计时之外,您显示的代码根本不正确:您执行100个连接(完全忽略最后一个连接以外的所有连接),然后,当您执行第一个execute调用时,您将传递一个局部变量
query\u stmt
,您仅在execute调用后初始化该变量

首先,确保代码正确,而不必担心时间:即,一个函数创建或接收一个连接,并在该连接上执行100或500次或任意次数的更新,然后关闭连接。一旦您的代码正常工作,您就可以考虑在其上使用
timeit

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


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

如果您正在评测代码并且可以使用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

我知道问题已经回答了,但我还是想加上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")
专注于一件具体的事情。磁盘I/O速度很慢,所以如果您只需要调整数据库查询,我会将其从测试中删除

如果您需要为数据库执行计时,请寻找数据库工具,例如询问查询计划,并注意性能不仅随精确查询和索引的不同而变化,还随数据负载(存储了多少数据)而变化

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

这将禁用垃圾收集,重复调用
函数\u to_repeat()
函数,并使用最精确的特定平台可用时钟计时这些调用的总持续时间

应将设置代码移出重复功能;例如,您应该首先连接到数据库,然后只对查询计时。使用
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)

将从脚本中获取全局变量
函数\u to_repeat
var1
var2
,并在每次重复时将其传递给函数

下面是史蒂文答案的简单包装。此函数不执行重复运行/平均,只是使您不必到处重复计时代码:)


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

这本书提供了许多值得一看的例子和标志。命令行的基本用法是:

$python-mtimeit“所有(范围(1000)内的为真)”
2000次循环,最佳5次:每循环161次
$python-mtimeit“全部([范围内(1000)]为真)
2000个循环,最佳值为5:116 usec/循环
使用
-h
运行以查看所有选项。关于
timeit
有一个很好的章节,展示了如何通过从命令行导入和多行代码字符串来运行模块

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

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)
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次试验
------------------------------
def测试_切片(L):
L[:]
时间=>0.0155023999972
------------------------------
def测试副本(L):
L.副本()
时间=>0.01651419999998
------------------------------
def测试副本(L):
抄送,深
'''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))
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")
import timeit

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

timeit.timeit(lambda: time_this(n=5000), number=1000)