Python有序垃圾收集字典?
我希望我的Python程序是确定性的,因此我在整个代码中广泛使用了Python有序垃圾收集字典?,python,garbage-collection,ordereddictionary,Python,Garbage Collection,Ordereddictionary,我希望我的Python程序是确定性的,因此我在整个代码中广泛使用了OrderedDicts。不幸的是,今天在调试内存泄漏时,我发现OrderedDicts有一个自定义的\uu del\uuu方法,使得它们在有周期时无法收集。很不幸,文档中没有关于这一点的警告 那我该怎么办?Python标准库中是否有任何与gc配合良好的确定性词典?我真的不想自己翻滚,尤其是像这样愚蠢的单行函数 还有,这是我应该提交错误报告的东西吗?我不熟悉Python库的程序,他们认为什么是bug。< /P> 编辑:我想最好的方
OrderedDicts
。不幸的是,今天在调试内存泄漏时,我发现OrderedDicts有一个自定义的\uu del\uuu
方法,使得它们在有周期时无法收集。很不幸,文档中没有关于这一点的警告
那我该怎么办?Python标准库中是否有任何与gc配合良好的确定性词典?我真的不想自己翻滚,尤其是像这样愚蠢的单行函数
还有,这是我应该提交错误报告的东西吗?我不熟悉Python库的程序,他们认为什么是bug。< /P>
编辑:我想最好的方法是只包含一个猴子补丁,以防用户碰巧运行像我这样的坏版本。听起来你已经在
orderedict
中找到了一个bug,它在你的2.7版本之后的某个时候被修复了。如果它不是在任何实际发布的版本中,也许你可以忽略它。但除此之外,是的,你需要一个变通办法
我建议您不要使用monkeypatchingcollections.OrderedDict
,而应该使用链接到的collections.OrderedDict
(它没有多余的\uu del\uu
)。如果没有其他问题,当有人说“我需要在2.6上运行这个,移植需要多少工作量”时,答案将是“少一点”
但还有两点:
重写所有内容以避免循环是一项巨大的工作
字典中有循环这一事实表明您做错了什么(通常对缓存或后向指针使用强引用),这可能会导致其他内存问题,也可能导致其他错误。因此,无论如何,这种努力可能是必要的
你还没有解释你想要完成什么;我怀疑“确定性”的东西只是一条红鲱鱼(特别是因为dict
s实际上是确定性的),所以最好的解决方案是s/orderedict/dict/g
但是,如果必须使用确定性,那么就不能依赖于循环收集器,因为它不是确定性的,这意味着终结器排序等都变得不确定性。这也意味着你的内存使用是不确定的,你可能最终得到的程序99.999%的时间都在你想要的内存范围内,但不是100%;如果这些界限非常重要,那可能比每次都失败更糟糕
同时,没有指定字典的迭代顺序,但在实践中,CPython和PyPy按照散列桶的顺序进行迭代,而不是值或键的id(内存位置),以及Jython和IronPython所做的任何事情(它们可能使用的是一些具有不同行为的底层Java或.NET集合;我还没有测试),钥匙的记忆顺序不太可能相关。(如何有效地基于类似的内容迭代散列表?)您可能会对使用id
进行散列的对象进行测试而感到困惑,但大多数对象都是基于值进行散列的
例如,以这个简单的程序为例:
d={}
d[0] = 0
d[1] = 1
d[2] = 2
for k in d:
print(k, d[k], id(k), id(d[k]), hash(k))
如果使用CPython 2.7、CPython 3.2和PyPy 1.9重复运行它,这些键将始终按0、1、2的顺序迭代。id
列也可能每次都相同(这取决于您的平台),但您可以通过多种方式修复此问题:以不同的顺序插入,颠倒值的顺序,使用字符串值而不是整数,将值分配给变量,然后插入这些变量而不是文字,等等。充分利用它,您可以获得id
列的每一个可能的顺序,但是每次键仍然以相同的顺序迭代
迭代的顺序是不可预测的,因为要预测它,您需要将hash(k)
转换为bucket索引的函数,这取决于您无法从Python访问的信息。即使它只是散列(k)%self.\u table\u size
,除非该\u table\u size
被公开给Python接口,否则它是没有帮助的。(这是一个复杂的插入和删除序列函数,原则上可以计算,但在实践中尝试是愚蠢的。)
但它是确定性的;如果您每次都以相同的顺序插入和删除相同的键,那么每次的迭代顺序都是相同的。听起来好像您在orderedict
中找到了一个bug,该bug在2.7版之后的某个时候被修复了。如果它不是在任何实际发布的版本中,也许你可以忽略它。但除此之外,是的,你需要一个变通办法
我建议您不要使用monkeypatchingcollections.OrderedDict
,而应该使用链接到的collections.OrderedDict
(它没有多余的\uu del\uu
)。如果没有其他问题,当有人说“我需要在2.6上运行这个,移植需要多少工作量”时,答案将是“少一点”
但还有两点:
重写所有内容以避免循环是一项巨大的工作
字典中有循环这一事实表明您做错了什么(通常对缓存或后向指针使用强引用),这可能会导致其他内存问题,也可能导致其他错误。因此,无论如何,这种努力可能是必要的
你还没有解释你想要完成什么;我怀疑“确定性”的东西只是一条红鲱鱼(特别是因为dict
s实际上是确定性的),所以最好的解决方案是s/orderedict/dict/g
但是如果决定论是必要的,你就不能依赖于循环收集器,因为它不是决定论的
>>> import collections
>>> del collections.OrderedDict.__del__