【问题标题】:Python Dictionary Access Faster than List Index AccessPython 字典访问比列表索引访问更快
【发布时间】:2021-03-04 04:53:23
【问题描述】:

我使用字典和列表进行了几次测试,以比较访问速度。除了 100 个项目在所有其他场景中(有更多项目)的情况外,字典访问比列表索引访问快。这背后的原因是什么?我能想到的唯一原因是字典初始化时分配了大内存和内存有限的列表,以及当项目数量增加时在列表上花费的复制时间。以下是我用于测试的代码:

a = np.random.rand(1000000, 15)
large_list_of_lists = a.tolist()
keys = list('abcdefghijklmno')
large_list_of_dicts = [dict(zip(keys, values)) for values in large_list_of_lists]

def test_large_list_of_lists():
    list_total = 0
    for list_row in large_list_of_lists:
        for i in range(15):
            list_total += list_row[i]
    print(f'List total: {list_total}')
            
def test_large_list_of_dicts():
    dict_total = 0
    for dict_row in large_list_of_dicts:
        for k in keys:
            dict_total += dict_row[k]            
    print(f'Dict total: {dict_total}')


def timef(func):
    start_time = time.time()
    func()
    print(f'Time: {time.time()-start_time}')    

for f in [test_large_list_of_lists, test_large_list_of_dicts]:
    timef(f)

List total: 7498408.687142285
Time: 0.9701709747314453
Dict total: 7498408.687142285
Time: 0.6495280265808105

【问题讨论】:

  • 什么时候用pass 替换+= 行?最好不要在基准测试中包含prints。 timef 在哪里?

标签: python python-3.x list dictionary


【解决方案1】:

一开始是一个非常有趣的测试用例,它根据用例的性能评估两种数据结构。正如我所看到的,您已经通过使其基于索引的访问来消除DictionaryList 的访问边缘,现在该访问将进入内存索引并获取数据,并且由于 Dictionary 将键存储为唯一哈希,因此对于任何 Dictionary 测试为了这个优势,case 必须比 List 慢,但恰恰相反。

第一次更改:

continue语句替换数学运算,想法是完全去除数据访问逻辑并了解是否存在差异,例如:

# Dictionary
for k in keys:
    continue

# List
for i in range(15):
    continue

但结果并不令人满意,即使删除了访问操作,它也会导致 Lists 出现相同问题的时间更长,Dictionary 的时间更少,这说明问题出在其他地方

第二次更改:

for i in range(15)for k in keys一样吗,好像不是这样,相反下面两个是一样的:

for i in [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14]:for k in keys 这实现了您正在寻找的魔法,正是 List 操作在 continue 或已经完成的计算中变得稍微快了一些。

简介:

在大型数据集中按顺序访问一组数字的操作中,range(15) 这样的操作效率较低,可能它比简单地读取数字具有过载,并且在 1500 万次迭代时总体影响是几毫秒的延迟,尽管不是很多缺点,但这似乎是这里的明显原因,如果你详细了解的话。

即使现在结果也不是精确到毫秒,我们知道这会随着硬件、cpu 等各种因素而变化,并且始终不在程序的控制范围内

【讨论】:

  • 我想你的推理是正确的;当范围被列表替换时,列表运行得更快。也许这是因为 range 是一个生成器。
  • 我可能不知道确切的原因,但有根据的猜测是 generator 会产生一个数字,与 pre 相比,在如此大的迭代中它会稍微慢一些-定义的列表。当然,尽管range 是一种更简洁的代码实践
猜你喜欢
  • 2020-12-14
  • 2020-09-05
  • 1970-01-01
  • 1970-01-01
  • 2019-09-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多