gpt4 book ai didi

Python C 扩展如果不将借用的引用归还给 Python Land,是否需要 Py_INCREF?

转载 作者:行者123 更新时间:2023-12-02 08:11:06 24 4
gpt4 key购买 nike

如果您获得借用的引用,但不将其归还给 Python,那么您应该在获得它时执行 Py_INCREF 操作,然后在完成后执行 Py_DECREF 操作有了它,还是这是多余的?

例如,这个简单的示例从 PyDict_GetItem 获取借用的引用,使用借用的引用执行一些操作,然后将 None 返回到 Python 空间。在此处使用借用的引用时是否需要 Py_INCREF/Py_DECREF

static PyObject PyFoo_bar(PyFoo *self, int field)
{
int field = 0;

PyFoo *child = NULL;

if (!PyArg_ParseTuple(args, "i", &field) {
return NULL;
}

child = PyDict_GetItem(self->children, field);

// Long code omitted that works on child
// Is it safe to do so without a Py_INCREF on child now followed by PY_DECREF later?

// NOT returning child here - just return None
Py_RETURN_NONE;
}

我担心的是,在调用 PyDict_GetItem 后,child 的引用计数可能会以某种方式降至零,然后在我使用它时释放它。这可能吗?我不这么认为,因为 GIL 没有掉在这里,但我不确定。

另一方面,我想知道在这里执行 Py_INCREF/Py_DECREF 是否是最佳实践。也许稍后我会放弃 GIL,或者稍后决定归还 child 。 Py_INCREF 很便宜。例如,这样做会更好吗:

child = PyDict_GetItem(self->children, field);
Py_INCREF(child);
// Long code omitted
Py_DECREF(child);
Py_RETURN_NONE;

最佳答案

这取决于中间“长代码”的作用。如果它执行您无法控制的 Python 代码,那么该代码完全有可能访问 self->children听写并删除 field ,此时,是的,其引用计数可以降至零。因此,您需要防止这种情况并添加 INCREF/DECREF。

请注意,任何 child 的使用将需要读取类型对象指针,该指针位于引用计数附近,因此后者将被加载到同一缓存行上。对于乱序执行,INCREF/DECREF 基本上是自由操作,因此性能没有理由忽略它们。

我能想到的执行 INCREF 的最佳原因是当“长代码”有多个退出点时(但不执行任意 python 代码或触摸 self->children ,如上所述) 。您必须为每个导出添加 DECREF,错过一个导出并导致难以调试的内存泄漏的风险很高。

关于Python C 扩展如果不将借用的引用归还给 Python Land,是否需要 Py_INCREF?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59870703/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com