0

我希望我的 Python 程序具有确定性,因此我一直OrderedDicts在整个代码中广泛使用。不幸的是,今天在调试内存泄漏时,我发现 OrderedDicts 有一个自定义__del__方法,只要有循环就无法收集它们。不幸的是,文档中没有关于此的警告。

那么我能做什么呢?Python 标准库中是否有任何与 gc 配合得很好的确定性字典?我真的不想自己动手,尤其是在像这样愚蠢的单行功能上。

另外,这是我应该提交错误报告的东西吗?我不熟悉 Python 库的过程,以及他们认为的错误。

编辑:看来这是一个已知的错误,早在 2010 年就已修复。我一定是安装了一个非常旧的 2.7 版本。我想最好的方法是只包含一个猴子补丁,以防用户碰巧运行像我这样的损坏版本。

4

3 回答 3

2

如果 __del__ 方法的存在对您来说有问题,只需将其删除:

>>> import collections
>>> del collections.OrderedDict.__del__

您将获得在参考周期中使用 OrderedDicts 的能力。您将失去让 OrderedDict 在删除后立即释放其所有资源。

于 2012-10-01T07:28:02.123 回答
1

听起来您已经找到了OrderedDict在您的 2.7 版本之后某个时间点修复的错误。如果它不在任何实际发布的版本中,也许您可​​以忽略它。但除此之外,是的,你需要一个解决方法。

我建议,而不是 monkeypatching collections.OrderedDict,您应该改用在 Python 2.4 或更高版本的文档中链接的Equivalent OrderedDict 配方(没有多余的)。如果不出意外,当有人走过来说“我需要在 2.6 上运行它,要移植多少工作”时,答案将是“少一点”……</p> collections.OrderedDict__del__

但还有两点:

重写所有内容以避免循环是一项巨大的努力。

您的字典中有循环这一事实是一个危险信号,表明您做错了什么(通常使用强引用作为缓存或反向指针),这可能会导致其他内存问题,并且可能会导致其他问题错误。因此,无论如何,这种努力可能是必要的。

你还没有解释你想要完成什么;我怀疑“确定性”的事情只是一个红鲱鱼(特别是因为dicts 实际上是确定性的),所以最好的解决方案是s/OrderedDict/dict/g.

但是如果确定性是必要的,你就不能依赖循环收集器,因为它不是确定性的,这意味着你的终结器排序等等都变得不确定。这也意味着你的内存使用是不确定的——你最终可能会得到一个程序,它在 99.999% 的时间里保持在你想要的内存范围内,但不是 100%;如果这些界限非常重要,那可能比每次都失败更糟糕。

同时,没有指定字典的迭代顺序,但实际上,CPython 和 PyPy 按哈希桶的顺序进行迭代,而不是值或键的 id(内存位置),以及 Jython 和 IronPython 所做的任何事情(他们可能正在使用一些具有不同行为的底层 Java 或 .NET 集合;我没有测试过),键的内存顺序不太可能是相关的。(你怎么能有效地基于类似的东西迭代一个哈希表?)你可能对使用idfor的对象进行测试感到困惑hash,但大多数对象是基于值的哈希值。

例如,以这个简单的程序为例:

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)为存储桶索引的函数,这取决于您无法从 Python 访问的信息。即使它只是hash(k) % self._table_size,除非它_table_size暴露给 Python 接口,否则它也无济于事。(这是插入和删除序列的复杂函数,原则上可以计算出来,但实际上尝试起来很愚蠢。)

但它是确定性的;如果每次都以相同的顺序插入和删除相同的键,则每次的迭代顺序都是相同的。

于 2012-10-01T04:51:14.377 回答
0

请注意,在 Python 2.7 中进行的修复以消除该__del__方法并阻止它们无法收集确实意味着每次使用OrderedDict(甚至是空的)都会导致引用循环,该引用循环必须被垃圾收集。有关更多详细信息,请参阅此答案

于 2017-10-25T15:51:36.930 回答