2

pickle 模块文档中有一段示例代码:

reader = pickle.load(open('save.p', 'rb'))

在第一次读取时,它看起来会分配一个系统文件描述符,读取其内容,然后“泄漏”打开的描述符,因为没有任何句柄可供调用close()。这让我想知道是否有任何隐藏的魔法可以解决这个问题。

深入研究源代码,我在 Modules/_fileio.c 中发现文件描述符被 fileio_dealloc() 析构函数关闭,这导致了真正的问题。

上面示例代码使用的文件对象的持续时间是多少?在该语句执行之后,该对象是否确实变得未被引用,因此 fd 是否会close(2)在未来的垃圾收集清理中受到真正的调用?如果是这样,示例行是一种好的做法,还是不应该指望释放 fd 从而冒内核每个进程描述符表耗尽的风险?

4

1 回答 1

3

上面示例代码返回的文件对象的持续时间是多少?

该代码不返回文件对象(正如 Q 的标题正确所说,它接收它作为参数)。

在当前的 CPython 中,文件将在函数返回时关闭(因为函数不会将文件对象的任何引用隐藏到更持久的位置)。在其他实现中,文件将“最终”关闭,但没有指定精确的时间。

取决于 CPython 的立即关闭语义(当未来的 CPython 转向更好的垃圾收集机制时,这可能会改变),虽然是一种非常传统的方法,但并不是最佳实践。

相反,最佳实践是使用以下with语句:

with open(...) as f:
  reader = pickle.load(f)

通过这种使用,文件的立即关闭(只要with语句的主体结束)在所有实现中都得到保证。

请注意,在 Python 2.5 中,您需要from __future__ import with_statement使用with. 在 2.6 或更高版本中,为此目的不需要这样的“从未来导入”(这是无害的,但如果您知道您永远不会在 2.5 下运行,那么它是多余的,最好删除)。

于 2010-03-23T01:42:22.513 回答