计算函数时间

1
2


要捕获我们的每个函数执行所需的时间,我们将使用 Python 的 timeit 模块。timeit 模块旨在允许 Python 开发人员通过在一致的环境中运行函数并使用尽可能相似的操作系统的时序机制来进行跨平台时序测量。
要使用 timeit,你需要创建一个 Timer 对象,其参数是两个 Python 语句。第一个参数是一个你想要执行时间的 Python 语句; 第二个参数是一个将运行一次以设置测试的语句。然后 timeit 模块将计算执行语句所需的时间。默认情况下,timeit 将尝试运行语句一百万次。 当它完成时,它返回时间作为表示总秒数的浮点值。由于它执行语句一百万次,可以读取结果作为执行测试一次的微秒数。你还可以传递 timeit 一个参数名字为 number,允许你指定执行测试语句的次数。以下显示了运行我们的每个测试功能 1000 次需要多长时间。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import matplotlib.pyplot as plt
%matplotlib inline
def test1():
l = []
for i in range(1000):
l = l + [i]

def test2():
l = []
for i in range(1000):
l.append(i)

def test3():
l = [i for i in range(1000)]

def test4():
l = list(range(1000))
1
2
3
4
5
6
7
8
9
10
import timeit
from timeit import Timer
t1 = Timer("test1()", "from __main__ import test1")
print("concat ",t1.timeit(number=1000), "milliseconds")
t2 = Timer("test2()", "from __main__ import test2")
print("append ",t2.timeit(number=1000), "milliseconds")
t3 = Timer("test3()", "from __main__ import test3")
print("comprehension ",t3.timeit(number=1000), "milliseconds")
t4 = Timer("test4()", "from __main__ import test4")
print("list range ",t4.timeit(number=1000), "milliseconds")
1
2
3
4
concat  1.0196415490549953 milliseconds
append 0.08268737967887319 milliseconds
comprehension 0.03390247851893946 milliseconds
list range 0.013240015113296977 milliseconds

作为一种演示性能差异的方法,我们用 timeit 来做一个实验。我们的目标是验证从列表从末尾 pop 元素和从开始 pop 元b素的性能。同样,我们也想测量不同列表大小对这个时间的影响。我们期望看到的是,从列表末尾处弹出所需时间将保持不变,即使列表不断增长。而从列表开始处弹出元素时间将随列表增长而增加。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
popzero = Timer("x.pop(0)",
"from __main__ import x")
popend = Timer("x.pop()",
"from __main__ import x")
data=[]
print("pop(0) pop()")
for i in range(1000000,100000001,1000000):
x = list(range(i))
pt = popend.timeit(number=1000)
x = list(range(i))
pz = popzero.timeit(number=1000)
print("%15.5f, %15.5f" %(pz,pt))
one_data={}
one_data['time']=i
one_data['pop(0)']=pz
one_data['pop()']=pt
data.append(one_data)
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
pop(0)   pop()
0.56428, 0.00026
1.46132, 0.00009
2.27953, 0.00007
3.11111, 0.00025
4.03941, 0.00007
5.01496, 0.00011
5.72766, 0.00008
6.41760, 0.00007
6.98101, 0.00016
7.69488, 0.00009
8.59127, 0.00008
9.39142, 0.00008
10.03456, 0.00007
10.85724, 0.00011
11.69828, 0.00008
12.37023, 0.00008
13.12709, 0.00010
13.89727, 0.00008
14.65594, 0.00007
15.49640, 0.00008
16.35027, 0.00008
17.00838, 0.00010
17.72517, 0.00008
19.29465, 0.00010
21.02476, 0.00008
21.60967, 0.00008
22.32767, 0.00008
22.62550, 0.00008
25.15527, 0.00009
24.14118, 0.00008
25.48768, 0.00009
24.84720, 0.00007
26.40644, 0.00008
26.62662, 0.00008
28.86800, 0.00008
27.79692, 0.00008

将比较列表和字典之间的 contains 操作的性能。在此过程中,我们将确认列表的 contains 操作符是 O(n),字典的 contains 操作符是 O(1)。我们将在实验中列出一系列数字。然后随机选择数字,并检查数字是否在列表中。如果我们的性能表是正确的,列表越大,确定列表中是否包含任意一个数字应该花费的时间越长。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import timeit
import random
data=[]
for i in range(10000,1000001,20000):
t = timeit.Timer("random.randrange(%d) in x"%i,
"from __main__ import random,x")
x = list(range(i))
lst_time = t.timeit(number=1000)
x = {j:None for j in range(i)}
d_time = t.timeit(number=1000)
print("%d,%10.3f,%10.3f" % (i, lst_time, d_time))
one_data={}
one_data['time']=i
one_data['lis_contains']=lst_time
one_data['dict_contains']=d_time
data.append(one_data)
data
1
2
3
4
5
6
7
10000,     0.075,     0.001
30000, 0.149, 0.001
50000, 0.235, 0.001
70000, 0.353, 0.001
90000, 0.449, 0.001
110000, 0.526, 0.001
130000, 0.614, 0.001
1
2


1
2
3
import pandas as pd 
row_data=pd.DataFrame.from_dict(data=data)
row_data.head()









































dict_contains lis_contains time
0 0.000865 0.074577 10000
1 0.000848 0.149025 30000
2 0.000817 0.235177 50000
3 0.001056 0.352916 70000
4 0.000893 0.448741 90000
1
pd.pivot_table(data=row_data,index='time').plot()
1
<matplotlib.axes._subplots.AxesSubplot at 0x1a28403b4a8>

png