python - Python 的关闭过程设置模块全局变量在哪里记录?

标签 python multithreading python-2.7 python-internals

CPython 有一个奇怪的行为,它在关闭期间将模块设置为 None。这会在我编写的一些多线程代码关闭期间搞砸错误记录。

我找不到有关此行为的任何文档。 PEP 432 中顺便提到过:

[...] significantly reducing the number of modules that will experience the "module globals set to None" behaviour that is used to deliberate break cycles and attempt to releases more external resources cleanly.

SO questions about this behaviourC API documentation mentions shutdown behaviour for embedded interpreters .

我还找到了 related thread on python-devrelated CPython bug :

This patch does not change the behavior of module objects clearing their globals dictionary as soon as they are deallocated.

这种行为记录在哪里?它是特定于 Python 2 的吗?

最佳答案

这种行为没有有很好的记录,并且存在于从大约 1.5-ish Python 3.4 的所有 Python 版本中:

As part of this change, module globals are no longer forcibly set to None during interpreter shutdown in most cases, instead relying on the normal operation of the cyclic garbage collector.

该行为的唯一文档是 moduleobject.c source code :

/* To make the execution order of destructors for global
   objects a bit more predictable, we first zap all objects
   whose name starts with a single underscore, before we clear
   the entire dictionary.  We zap them by replacing them with
   None, rather than deleting them from the dictionary, to
   avoid rehashing the dictionary (to some extent). */

请注意,将值设置为 None 是一种优化;另一种方法是从映射中删除名称,这会导致不同的错误(NameError 异常而不是 AttributeError 在尝试使用来自 __del__< 的全局变量时 处理程序)。

正如您在邮件列表中发现的那样,这种行为早于循环垃圾收集器;它是 added in 1998 ,而循环垃圾收集器是 added in 2000 .由于函数对象总是引用模块 __dict__ 模块中的所有函数对象都涉及循环引用,这就是 __dict__ 需要在 GC 发挥作用之前清除的原因。

即使添加了循环 GC,它也会保留在原地,因为循环中可能存在具有 __del__ 方法的对象。这些aren't otherwise garbage-collectable ,并且清除模块字典至少会从此类循环中删除模块 __dict__ 。不这样做将使该模块的所有引用的全局变量保持事件状态。

PEP 442 所做的更改现在,垃圾收集器可以使用提供 __del__ 终结器的对象清除循环引用,从而无需清除模块 __dict__ 在大多数情况下。代码是still there但这只有在 __dict__ 属性仍然存在时才会触发,即使在将 sys.modules 的内容移动到弱引用并在解释器关闭时启动 GC 收集运行之后;模块终结器只是减少它们的引用计数。

关于python - Python 的关闭过程设置模块全局变量在哪里记录?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25649676/

相关文章:

python - 用 Python 封装一个 C 程序,将自定义文件读取到二维数组中

java - RxJava 线程安全

Python:寻找最长路径

python - 如何从 pycurl 多 curl 请求中获取响应正文

python - 未找到命名游标的模块

python - 如何根据图像质量确定使用哪种 OCR 方法

python - 如何在 Pandas/Dask 中按具有可变 bin 的列离散化大数据帧

c++ - 为什么 pthread_join 给出这个错误? [错误] 从 'void*' 到 'void**' 的无效转换 [-fpermissive]

c# - Mono 2.8.1 断言 mono_wsq_count (wsq) == 0

python - 在 python 中保存 json 响应