python GIL : Do all participants in an expression have ref count incremented for the duration of the expression?

标签 python gil

假设我有一个简单的 C++ 类:

class Widget
{
public:
    Widget() :
            x(1)
    { }

    void sleep()
    {
        sleep(x);
    }

private:
    int x;
};

Widget::sleep block ,所以我想释放 GIL 以便 Python 可以做一些其他的事情,所以我将 Widget::sleep 包装在一个像这样的功能:

static void pyWidgetSleep(Widget& self)
{
    PyThreadState* state = PyEval_SaveThread();
    self.sleep();
    PyEval_RestoreThread(state);
}

为了完整起见,绑定(bind)代码如下所示:

BOOST_PYTHON_MODULE(libnative)
{
    boost::python::class_<Widget>("Widget")
        .def("sleep", &pyWidgetSleep);
}

我有一个简单的 Python 脚本,如下所示:

import libnative
import threading

class C:
    def __init__(self):
        self.x = libnative.Widget()
        self.sleeping = False

    def foo(self):
        self.sleeping = True
        self.x.sleep()

c = C()
t = threading.Thread(target=c.foo)
t.start()
while not c.sleeping:
    pass
del c.x

表达式中的所有参与者是否都在表达式持续时间内增加了他们的引用计数? c.xC.foo 中使用时唯一引用的是 ct.start() 之后的行> 随手删除。 由于 pyWidgetSleep 释放 GIL,del c.x 可能会减少对 Widget 实例的最后引用,从而导致未定义的行为。


我无法在我的机器上进行此中断,这似乎很好地表明它按我预期的方式工作,但引用计数并未记录到如此清晰的程度 (或者,至少,我似乎找不到它)。 CPython 的相关部分似乎是 PyEval_EvalCodeEx,它看起来像是将 Py_INCREF 应用于所有参数 涉及一个函数调用,但我可能完全不关心那个。

最佳答案

这个问题的答案是是的,它是安全的。这是由于在 Python 中调用成员函数的方式造成的。考虑是否 Widget 是用 Python 实现的:

class Widget:
    def __init__(self):
        self.x = 1

    def sleep(self):
        os.sleep(self.x)

注意 Widget.sleep 的第一个参数是 self 吗?引用计数在调用期间递增!回想起来似乎很明显......

关于 python GIL : Do all participants in an expression have ref count incremented for the duration of the expression?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12945457/

相关文章:

python - 为什么非常小的 checkinterval 不会减慢 python3 中 CPU 密集型多线程的速度?

python多线程性能

python - 为什么Python解释器不是线程安全的?

Python正则表达式从字符串中获取URL

python - Windows 8 (Anaconda) 上的 rpy2 安装错误

python - 销毁子解释器后释放 GIL

python - 主 python 线程的 PyThreadState* 是否应为 NULL?

python - 在 Python 中通过 ssh 实现 hdf5

python - 转换元组列表中元组的一项

python - 在正则表达式组上使用数学函数