Запустите код Cython, когда модуль расширения будет собирать мусор - PullRequest
0 голосов
/ 28 января 2019

Есть ли способ зарегистрировать функцию в модуле расширения Cython, чтобы эта функция вызывалась, когда сборщик мусора Python уничтожает объект модуля?

Что-то вроде

def __dealloc__(...)

на уровне модуля?

1 Ответ

0 голосов
/ 29 января 2019

Я не уверен, что есть явный / официальный способ добиться этого.Тем не менее, вы можете добавить глобальную переменную, которая будет уничтожена при освобождении модуля cython:

# foo.pyx:
class Observer:
    def __init__(self):
        print("module initialized")

    def __del__(self):
        print ("module deleted")

_o=Observer()

Тем не менее, его цитонизация через cythonize foo.pyx -i не приведет к желаемому эффекту:

[$] python -c `import foo`
module initialized

нет "удаленного модуля", напечатанного на консоли!

Проблема: в любом случае невозможно перезагрузить расширение Cython (например, через importlib.reload()), поэтому оно освобождается только когда Pythonпереводчик выключенНо тогда нет необходимости освобождать ресурсы ...

Cython хранит все глобальные Python-переменные в глобальной C-переменной, которая называется static PyObject *__pyx_d; в цитонизированном C-источнике;это просто Python-словарь.Однако, поскольку в этом не уничтоженном словаре есть ссылка на глобальный _o, счетчик ссылок _o никогда не станет равным 0, поэтому объект не будет уничтожен.

При установке generate_cleanup_code=True можно заставить Cython сгенерировать функцию очистки, которая будет помещена в m_free -слот структуры определения PyModuleDef .Например, со следующим файлом установки:

from distutils.core import setup

from Cython.Build import cythonize
from Cython.Compiler import Options

Options.generate_cleanup_code = True  #  this is important!

setup(
    name = "foo",
    ext_modules = cythonize("foo.pyx"),
)

А теперь после python setup.py build_ext -i:

[$] python -c "import foo"
module initialized
module deleted

он работает как положено.


Потому что тамне равен reload для расширений Cython, «удаленный модуль» будет виден только при вызове module_dealloc.

Однако, когда первый листинг был чисто Python, мы бытакже смотрите module deleted, если importlib.reload(foo) были вызваны.В этом случае «module_dealloc» не используется, но все ссылки на глобальные _o будут очищены, а объект будет уничтожен.

В зависимости от того, что нужно, это может быть как ожидаемое, так и неожиданное поведение.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...