TOC

Python 打开文件的方式

有同事排查 Python 项目问题的时候指出一处 open 没有关闭可能会导致句柄泄露 Handle Leak。
PS: 句柄泄漏的危害:大量资源占用可能导致性能下降,甚至由于可打开文件数达到极限,服务无法继续向外提供服务。

我看了之后告诉他,此处函数退出之后句柄会自动关闭,他还不信,下去自己研究了一会儿,可能是百度一下,过一会儿说好像确实是这样,不过他仍然很疑惑,那么 with open 的作用是什么呢?

一般我们常用上下文管理的方式(with open)来打开文件,这样可以自动关闭句柄,这是一个好的实践。

  1. 退出函数之后文件描述符的自动关闭是 CPython GC (垃圾回收机制) 的特性,非 Python 语言规范。
  2. 根据 CPython 的 GC 策略(引用计数),如果有引用,文件描述符不会被关闭,这是一个非常严重的潜在风险。
    大部分时候我们可能没有引用文件描述符,但是不能排除可能性。
    万一出现句柄泄漏,在代码库中排查可能的未关闭引用会比较麻烦。
  3. 上下文管理会自动处理异常,相当于我们的 close 方法放在 finally 块中。

无关的事情:进程退出时的句柄

进程退出时如果有没有关闭的句柄,

  1. 如果程序正常退出,
  2. 语言可能会处理一道,清理相关数据
  3. 系统会处理一道
  4. 如果程序异常退出,则只有靠系统了

至少我看到 POSIX 中有相关规定,无论任何原因或任何方式的退出,都应该:

All of the file descriptors, directory streams, conversion descriptors, and message catalog descriptors open in the calling process shall be closed.

PS: 其中提到的:

  1. 文件描述符 File Descriptors
  2. 目录流 Directory Streams
  3. 转换描述符 Conversion Descriptors
  4. 消息编码描述符 Message Catalog Descriptors

后面三个是个啥?