为什么在Python迭代字典很慢?
在本文中,我们将讨论为什么在Python迭代 dict 如此缓慢?在得出任何结论之前,让我们先看看PythonNumPy 数组和字典之间的性能差异:
Python
# import modules
import numpy as np
import sys
# compute numpy performance
def np_performance():
array = np.empty(100000000)
for i in range(100000000):
array[i] = i
print("SIZE : ",
sys.getsizeof(array)/1024.0**2,
"MiB")
# compute dictionary performance
def dict_performance():
dic = dict()
for i in range(100000000):
dic[i] = i
print("SIZE : ",
sys.getsizeof(dic)/1024.0**2,
"MiB")
Python3
# compute time taken
%time np_performance()
Python3
# compute time taken
%time dict_performance()
在上面的Python脚本中,我们有两个函数:
- np_performance:此函数为 10,00,000 个元素创建一个空的 NumPy 数组,并迭代整个数组,将单个元素的值更新为迭代器位置(在本例中为“i”)
- dict_performance:此函数为 10,00,000 个元素创建一个空字典,并迭代整个字典,将单个元素的值更新为迭代器位置(在本例中为“i”)
最后,调用sys.getsizeof()函数来计算各个数据结构的内存使用情况。
现在我们调用这两个函数,为了测量每个函数所花费的时间,我们使用%time函数,它为我们提供了Python语句或表达式的执行时间。 %time函数既可以用作线条魔法,也可以用作单元魔法:
- 在内联模式下,您可以对单行语句进行计时(尽管可以使用分号链接多个语句)。
- 在单元格模式下,您可以为单元格主体计时(紧随其后的语句会引发错误)。
使用 %time 方法从内联模式调用这些函数:
蟒蛇3
# compute time taken
%time np_performance()
输出:
蟒蛇3
# compute time taken
%time dict_performance()
输出:
正如我们所见,迭代 NumPy 数组和Python字典之间的 Wall time 存在很大差异。
- 这种性能差异是由于数组和字典之间的内部工作差异造成的,因为在Python 3.6 之后, Python中的字典基于 HashTable 和元素数组的混合。因此,无论何时我们从字典中取出/删除一个条目,而不是从该特定位置删除一个键,它允许将下一个键替换为已删除键的位置。 Python字典所做的是用一个表示空的虚拟值替换哈希数组中的值。因此,当您遇到这些虚拟空值时,它会不断迭代,直到找到下一个实值键。
- 由于可能有很多空白空间,我们将在没有任何实际好处的情况下遍历,因此字典通常比它们的数组/列表对应物慢。
- 对于大型数据集,内存访问将是瓶颈。字典是可变的,并且比数组或(命名的)元组占用更多的内存(有效组织时,不复制类型信息)。