У меня есть вопрос о внутренней работе инициализации суб-интерпретатора Python (из Python / C API) и функции Python id()
. Точнее, об обработке глобальных объектов модуля в контейнерах WSGI Python (например, uWSGI, используемый с nginx и mod_wsgi в Apache).
Следующий код работает как ожидалось (изолированно) в обеих упомянутых средах, но я не могу объяснить себе , почему функция 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 с одним основным процессом и двумя рабочими; и в mod_wsgi, используя режим deamon с двумя процессами и одним потоком на процесс. Типичный вывод:
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
ул (а) = два
на всех остальных. Как вы можете видеть, id()
(место в памяти) как класса, так и экземпляра класса остается одинаковым в обоих процессах (первая / вторая загрузка выше), в то время как экземпляры класса одновременно живут в отдельный контекст (в противном случае второй запрос будет показывать «два» вместо «один»)!
Я подозреваю, что ответ может быть подсказан Python docs:
id(object)
Возвращает «идентичность» объекта. Это целое число (или длинное целое), которое
гарантированно будет уникальным и постоянным для этого объекта в течение срока его службы. Два
объекты с неперекрывающимися временами жизни могут иметь одинаковое значение id()
.
Но если это действительно является причиной, меня беспокоит следующее утверждение, которое утверждает, что значение id()
является адресом объекта!
Хотя я ценю тот факт, что это вполне может быть просто «умная» функция Python / C API, которая решает (или, скорее, исправляет ) проблему кэширования ссылок на объекты (указатели) в 3-м модули расширения партии , я все еще нахожу это поведение несовместимым с ... ну, здравым смыслом. Может ли кто-нибудь объяснить это?
Я также заметил, что mod_wsgi импортирует модуль в каждом процессе (т.е. дважды ), в то время как uWSGI импортирует модуль только один раз для обоих процессов. Поскольку основной процесс uWSGI выполняет импорт, я полагаю, что он заполняет дочерние элементы копиями этого контекста. После этого оба работника работают независимо (глубокое копирование?), Одновременно используя, по-видимому, одни и те же адреса объектов. (Кроме того, работник перезагружается в исходный контекст после перезагрузки.)
Я прошу прощения за такой длинный пост, но я хотел дать достаточно подробностей.
Спасибо!