python timeti模块使用

前言

python可以使用timeit模块来测试小段代码的运行时间.
timeit主要的函数有timeitrepeat (还有default_timer, 用法可见文章)

timeitrepeat的实现

1
2
3
4
5
6
7
8
9
def timeit(stmt="pass", setup="pass", timer=default_timer,
number=default_number, globals=None):
"""Convenience function to create Timer object and call timeit method."""
return Timer(stmt, setup, timer, globals).timeit(number)

def repeat(stmt="pass", setup="pass", timer=default_timer,
repeat=default_repeat, number=default_number, globals=None):
"""Convenience function to create Timer object and call repeat method."""
return Timer(stmt, setup, timer, globals).repeat(repeat, number)

在上面的代码中可见, 无论是timeit还是repeat都是先 生成Timer对象, 然后调用了Timer对象的timeitrepeat函数。

参数

  1. stmt: 用于传入要测试时间的代码, 可以直接接受字符串的表达式, 也可以接受单个变量, 也可以接受函数
    PS: 传入函数时要使用参数setup导入函数

  2. setup: 传入stmt的运行环境, 比如stmt中使用到的参数、变量, 要导入的模块等。可以写一行语句, 也可以写多行语句, 写多行语句时要用**分号;**隔开语句。

  3. number: 要测试的代码的运行次数, 默认100000次, 对于耗时的代码, 运行太多次会比较慢, 此时建议自己修改一下运行次数

  4. repeat: 指测试要重复几次, 每次的结果构成列表返回, 默认3次

用法

在使用timeit模块时, 有两种方式

  1. 直接使用timeit.timeit()tiemit.repeat()
  2. 先用timeit.Timer()来生成一个Timer对象, 然后再用Timer对象用timeit()repeat()函数, 相对灵活一些。

repeat的优点

可以多次重复测试, 并可以对测试所得的执行时间取最小值, 平均值, 最大值, 更方便分析。

例子

例子1

测试一个列表推导式 比正常写for循环快多少

1
2
3
4
5
6
7
8
9
10
11
12
13
import timeit

foo = """
sum = []
for i in range(1000):
sum.append(i)
"""

print(timeit.timeit(stmt="[i for i in range(1000)]", number=100000)) # 传入的是字符串表达式
print(timeit.timeit(stmt=foo, number=100000)) # 传入的是变量
# 输出:
# 3.0182870961591375
# 8.967388768466217

例子2

使用timeit来比较递归斐波那契迭代斐波那契的时间效率差异

注意

代码中分别定义了两个函数,
要测试这两个函数, 需导入这两个函数,
即设置setup = from __main__ import recursive_fibonacci,
表明从当前运行的代码下导入这两个函数。
如果是其他模块的, 则要import别的模块进来

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
import timeit

def recursive_fibonacci(nth_item):
if nth_item == 1 or nth_item == 2:
return 1
elif nth_item <= 0:
return 0

return recursive_fibonacci(nth_item - 1) + recursive_fibonacci(nth_item - 2)

def loop_fibonacci(nth_item):
if nth_item == 1 or nth_item == 2:
return 1
elif nth_item <= 0:
return 0

first_item, second_item = 1, 1

for x in range(nth_item-2):
first_item, second_item = second_item, first_item + second_item

return second_item


if __name__ == "__main__":
print(
timeit.timeit(
stmt="recursive_fibonacci(20)",
setup="from __main__ import recursive_fibonacci", number=10000
)
)
print(
timeit.timeit(
stmt="loop_fibonacci(20)",
setup="from __main__ import loop_fibonacci",
number=10000
)
)

例子3

setup参数的灵活使用, 设置stmt运行环境的详细例子
涉及

  • 导入模块
  • 变量定义
  • 函数调用
  • 多行写setup要加分号的方式
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
import timeit

x = """
say_hi.ParseFromString(p)
"""

y = """
simplejson.loads(x)
"""

print(
timeit.timeit(
stmt=x,
setup="import say_hi_pb2;"
"say_hi = say_hi_pb2.SayHi();"
"say_hi.id = 13423;"
"say_hi.something = 'axiba';"
"say_hi.extra_info = 'xiba';"
"p =say_hi.SerializeToString()",
number=1000000
)
)

print(
timeit.timeit(
stmt=y,
setup="import simplejson; "
"json={"
"'id': 13423,"
"'something': 'axiba',"
"'extra_info': 'xiba',"
"};"
"x = simplejson.dumps(json)",
number=1000000
)
)

命令行调用timeit

1
2
3
4
5
6
7
8
9
10
python -m timeit [-n N] [-r N] [-s S] [-t] [-c] [-h] [statement...]

-n N 执行指定语句的次数
-r N 重复测量的次数(默认3次)
-s S 指定初始化代码构建环境的导入语句(默认pass)
python 3.3新增
-t 使用time.time() (不推荐)
-c 使用time.clock() (不推荐)
-v 打印原始计时结果
-h 帮助
1
2
3
4
5
6
$ python -m timeit '"-".join(str(n) for n in range(100))'
loops, best of 3: 40.3 usec per loop
$ python -m timeit '"-".join([str(n) for n in range(100)])'
loops, best of 3: 33.4 usec per loop
$ python -m timeit '"-".join(map(str, range(100)))'
loops, best of 3: 25.2 usec per loop
-------本 文 结 束 感 谢 您 的 阅 读-------
赞赏一杯咖啡
0%