Python容器相關簡單效能測試

faf4r發表於2024-08-24

今天看了《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()有消耗的原因




# 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相關。

相關文章