id()
我对 Python 子解释器初始化(来自 Python/C API)和 Python函数的内部工作有疑问。更准确地说,关于在 WSGI Python 容器中处理全局模块对象(如 uWSGI 与 nginx 和 Apache 上的 mod_wsgi 一起使用)。
以下代码在上述两种环境中都按预期(隔离)工作,但我无法向自己解释为什么该id()
函数总是为每个变量返回相同的值,而不管它在哪个进程/子解释器中执行。
from __future__ import print_function
import os, sys
def log(*msg):
print(">>>", *msg, file=sys.stderr)
class A:
def __init__(self, x):
self.x = x
def __str__(self):
return self.x
def set(self, x):
self.x = x
a = A("one")
log("class instantiated.")
def application(environ, start_response):
output = "pid = %d\n" % os.getpid()
output += "id(A) = %d\n" % id(A)
output += "id(a) = %d\n" % id(a)
output += "str(a) = %s\n\n" % a
a.set("two")
status = "200 OK"
response_headers = [
('Content-type', 'text/plain'), ('Content-Length', str(len(output)))
]
start_response(status, response_headers)
return [output]
我已经在 uWSGI 中用一个主进程和 2 个工作进程测试了这段代码;并在 mod_wsgi 中使用具有两个进程和每个进程一个线程的守护程序模式。典型的输出是:
pid = 15278
id(A) = 139748093678128
id(a) = 139748093962360
str(a) = 一
在第一次加载时,然后:
pid = 15282
id(A) = 139748093678128
id(a) = 139748093962360
str(a) = 一
在第二个,然后
PID = 15278 | pid = 15282
id(A) = 139748093678128
id(a) = 139748093962360
str(a) = 两个
每隔一段时间。如您所见,id()
类和类实例的(内存位置)在两个进程中保持相同(上面的第一次/第二次加载),而同时类实例存在于单独的上下文中(否则第二个请求将显示“二”而不是“一”)!
我怀疑 Python 文档可能暗示了答案:
id(object)
:返回对象的“身份”。这是一个整数(或长整数),保证该对象在其生命周期内是唯一且恒定的。具有不重叠生命周期的两个对象可能具有相同的
id()
值。
但如果这确实是原因,我会被下一个声称该id()
值是对象地址的声明所困扰!
虽然我很欣赏这很可能只是 Python/C API 的“聪明”功能,可以解决(或更确切地说是修复)在 3rd 方扩展模块中缓存对象引用(指针)的问题,但我仍然发现这种行为不一致与...嗯,常识。有人可以解释一下吗?
我还注意到 mod_wsgi 在每个进程中导入模块(即两次),而 uWSGI 只为两个进程导入模块一次。由于 uWSGI 主进程进行导入,我想它用该上下文的副本为子进程播种。两个工人之后独立工作(深拷贝?),同时使用相同的对象地址,看似。(此外,工作人员在重新加载时会重新初始化为原始上下文。)
我为这么长的帖子道歉,但我想提供足够的细节。谢谢!