运行 扩展模块被垃圾回收时的 cython 代码
Run cython code when extension module gets garbage collected
有没有办法在 Cython 扩展模块中注册一个函数,以便在 Python 垃圾收集器销毁模块对象时调用该函数?
类似
def __dealloc__(...)
在模块级别?
我不确定是否有 explicit/official 方法可以做到这一点。但是,您可以添加一个全局变量,当释放 cython 模块时,该变量将被销毁:
# foo.pyx:
class Observer:
def __init__(self):
print("module initialized")
def __del__(self):
print ("module deleted")
_o=Observer()
然而,通过 cythonize foo.pyx -i
对其进行 cythonizing 不会产生预期的效果:
[$] python -c `import foo`
module initialized
没有 "module deleted" 打印到控制台!
问题:无论如何都无法重新加载 cython 扩展(例如通过 importlib.reload()
),因此只有当 Python 解释器关闭时它才会被释放。但是这样就不需要重新分配资源了...
Cython 将所有全局 Python 变量保存在全局 C 变量中,在 cython 化的 C 源代码中称为 static PyObject *__pyx_d;
;这只是一个 Python 字典。但是,因为在这个未销毁的字典中有对全局 _o
的引用,所以 _o
的引用计数永远不会变为 0,因此对象不会被销毁。
通过设置 generate_cleanup_code=True
可以强制 Cython 生成一个清理函数,该函数将被放入 m_free
-slot of the 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
它按预期工作。
因为 Cython 扩展没有 reload
,只有在调用 module_dealloc
时才能看到 "module deleted"。
但是,当第一个列表是纯 Python 时,如果调用 importlib.reload(foo)
,我们也会看到 module deleted
。在这种情况下 "module_dealloc" 未被使用,但所有对全局 _o
的引用将被清除并且对象将被销毁。
这取决于一个人想要什么,它可能是预期的或意外的行为。
有没有办法在 Cython 扩展模块中注册一个函数,以便在 Python 垃圾收集器销毁模块对象时调用该函数?
类似
def __dealloc__(...)
在模块级别?
我不确定是否有 explicit/official 方法可以做到这一点。但是,您可以添加一个全局变量,当释放 cython 模块时,该变量将被销毁:
# foo.pyx:
class Observer:
def __init__(self):
print("module initialized")
def __del__(self):
print ("module deleted")
_o=Observer()
然而,通过 cythonize foo.pyx -i
对其进行 cythonizing 不会产生预期的效果:
[$] python -c `import foo`
module initialized
没有 "module deleted" 打印到控制台!
问题:无论如何都无法重新加载 cython 扩展(例如通过 importlib.reload()
),因此只有当 Python 解释器关闭时它才会被释放。但是这样就不需要重新分配资源了...
Cython 将所有全局 Python 变量保存在全局 C 变量中,在 cython 化的 C 源代码中称为 static PyObject *__pyx_d;
;这只是一个 Python 字典。但是,因为在这个未销毁的字典中有对全局 _o
的引用,所以 _o
的引用计数永远不会变为 0,因此对象不会被销毁。
通过设置 generate_cleanup_code=True
可以强制 Cython 生成一个清理函数,该函数将被放入 m_free
-slot of the 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
它按预期工作。
因为 Cython 扩展没有 reload
,只有在调用 module_dealloc
时才能看到 "module deleted"。
但是,当第一个列表是纯 Python 时,如果调用 importlib.reload(foo)
,我们也会看到 module deleted
。在这种情况下 "module_dealloc" 未被使用,但所有对全局 _o
的引用将被清除并且对象将被销毁。
这取决于一个人想要什么,它可能是预期的或意外的行为。