Python容器相关简单性能测试
今天看了《Python工匠》容器一章,对其中一些内容衍生兴趣,简单测试了一下其性能
from timeit import timeit
# 1.生成器遍历和列表遍历的速度比较
def gen(n=100000):
for i in range(n):
yield i
def lis(n=100000):
return [i for i in range(n)]
def perf_gen():
for i in gen():
pass
def perf_lis():
for i in lis():
pass
t_gen = timeit(setup="from __main__ import perf_gen", stmt="perf_gen()", number=10000)
t_lis = timeit(setup="from __main__ import perf_lis", stmt="perf_lis()", number=10000)
print(t_gen) # 3.005467499999213(n=10000) 28.504840099994908(n=100000)
print(t_lis) # 1.8407773000071757(n=10000) 24.375115999995614(n=100000)
# 结论
# 元素少的时候,遍历列表比生成器要快,我认为是因为生成器要实时生成,但列表已经生成好了
# 元素很多时,两者差距不大
# 总之还是得根据实际情况来使用,二者性能差距并不大
# 2.insert到不同位置的时间区别
def insert_head(n):
li = []
for i in range(n):
li.insert(0, i)
def insert_end(n):
li = []
for i in range(n):
li.insert(li.__len__(), i)
def insert_end2(n):
li = []
for i in range(n):
li.insert(-1, i)
def append(n):
li = []
for i in range(n):
li.append(i)
t_insert_head = timeit(setup="from __main__ import insert_head", stmt="insert_head(10000)", number=1000)
print(t_insert_head)
t_insert_end = timeit(setup="from __main__ import insert_end", stmt="insert_end(10000)", number=1000)
print(t_insert_end)
t_insert_end2 = timeit(setup="from __main__ import insert_end2", stmt="insert_end2(10000)", number=1000)
print(t_insert_end2)
t_append = timeit(setup="from __main__ import append", stmt="append(10000)", number=1000)
print(t_append)
# 8.290992399997776
# 0.5631236000044737
# 0.26824749998922925
# 0.18099470000015572
# insert时,头插和尾插因为底层实现,必定头插慢
# 而append应该有专门优化过的,比同操作的insert还快,不知道是不是len()有消耗的原因
# 下面看下双端队列deque的性能
from collections import deque
def deque_insert_head(n):
li = deque()
for i in range(n):
li.appendleft(i)
def deque_insert_end(n):
li = deque()
for i in range(n):
li.append(i)
t_deque_insert_head = timeit(setup="from __main__ import deque_insert_head", stmt="deque_insert_head(10000)", number=1000)
print(t_deque_insert_head)
t_deque_insert_end = timeit(setup="from __main__ import deque_insert_end", stmt="deque_insert_end(10000)", number=1000)
print(t_deque_insert_end)
# 0.22433799999998882
# 0.22514420002698898
# 相比list.append差一点,但是首位都快,且与list差距不大
# 3.判断成员是否存在,长短列表用集合判断的时间差别,长列表在头尾位置判断的差别
t_long_list_head = timeit(setup="li = list(range(100000))", stmt="0 in li", number=10000)
t_long_list_rear = timeit(setup="li = list(range(100000))", stmt="99999 in li", number=10000)
t_short_list_head = timeit(setup="li = list(range(100))", stmt="0 in li", number=10000)
t_short_list_rear = timeit(setup="li = list(range(100))", stmt="99 in li", number=10000)
print(t_long_list_head)
print(t_long_list_rear)
print(t_short_list_head)
print(t_short_list_rear)
# 0.00011639999866019934
# 3.8965106999967247
# 0.00011199999426025897
# 0.00371659999655094
# t_long_set_head = timeit(setup="li = list(range(100000))", stmt="0 in set(li)", number=10000)
# t_long_set_rear = timeit(setup="li = list(range(100000))", stmt="99999 in set(li)", number=10000)
# t_short_set_head = timeit(setup="li = list(range(100))", stmt="0 in set(li)", number=10000)
# t_short_set_rear = timeit(setup="li = list(range(100))", stmt="99 in set(li)", number=10000)
# print(t_long_set_head)
# print(t_long_set_rear)
# print(t_short_set_head)
# print(t_short_set_rear)
# 22.197511299993494
# 21.99846269999398
# 0.00856279999425169
# 0.008391000010306016
# 由于上面使用集合时每次都重新创建了集合,存在额外损耗,比较不公平。
# 应该提前将列表转换为集合,查询时直接查询使用
t_long_set_head = timeit(setup="li = set(range(100000))", stmt="0 in li", number=10000)
t_long_set_rear = timeit(setup="li = set(range(100000))", stmt="99999 in li", number=10000)
t_short_set_head = timeit(setup="li = set(range(100))", stmt="0 in li", number=10000)
t_short_set_rear = timeit(setup="li = set(range(100))", stmt="99 in li", number=10000)
print(t_long_set_head)
print(t_long_set_rear)
print(t_short_set_head)
print(t_short_set_rear)
# 0.0001294999965466559
# 0.0001736000122036785
# 0.00012630000128410757
# 0.00013259999104775488
# 可以看出集合确实不受容器大小、元素位置灯限制,只与hash相关。