我正在填写一个包含大约10,000,000个项目的python dict。我对dict(或hashtables)的理解是,当有太多的元素进入它们时,需要调整大小,这个操作花费了相当长的时间。
有没有办法对python dict说你将在其中存储至少n个项目,以便它可以从一开始就分配内存?或者这种优化对我的跑步速度没有任何好处?
(不,我没有检查过我的小脚本的缓慢是因为这个,我实际上现在不会怎么做。不过我会用Java做的,设置初始容量HashSet右)
答案 0 :(得分:18)
首先,我听说有传言说您可以在初始化时设置字典的大小,但我从未见过任何文档或PEP描述如何完成此操作。
考虑到这一点,我对您的物品数量进行了分析,如下所述。虽然每次我建议继续前进而不用担心它可能需要一些时间来调整字典的大小,至少在你可以测试它的性能之前。
在确定调整大小时我们关注的两个规则是元素的数量和调整大小的因素。字典将在添加2/3标记的元素添加2/3时自行调整大小。低于50,000个元素,它将增加4倍,高于该数量2倍。使用您对10,000,000个元素(在2 ^ 23和2 ^ 24之间)的估计,您的字典将自行调整15次(低于50k的7倍, 8次以上)。另一个调整大小将超过11,100,000。
调整和替换哈希表中的当前元素确实需要一些时间,但我想知道你是否注意到它附近代码中的其他内容。我只是将一个时序套件放在一起比较沿着每个边界的五个位置插入的字典大小为2 ^ 3到2 ^ 24,并且“边界”添加平均比“非边界”添加长0.4纳秒。这长0.17%......可能是可以接受的。所有操作的最小值为0.2085微秒,最大值为0.2412微秒。
希望这是有洞察力的,如果你确实检查了代码的性能,请跟进编辑!我在字典内部的主要资源是Brandon Rhodes在PyCon 2010上的精彩演讲:The Mighty Dictionary
答案 1 :(得分:2)
是的,你可以而且这里是我在另一个人的问题中找到的与你有关的解决方案:
d = {}
for i in xrange(4000000):
d[i] = None
# 722ms
d = dict(itertools.izip(xrange(4000000), itertools.repeat(None)))
# 634ms
dict.fromkeys(xrange(4000000))
# 558ms
s = set(xrange(4000000))
dict.fromkeys(s)
# Not including set construction 353ms
这些是初始化具有特定大小的字典的不同方法。