Python GIL:表达式中的所有参与者是否在表达式的持续时间内都增加了ref count?

2024-10-06 12:14:07 发布

您现在位置:Python中文网/ 问答频道 /正文

让我说我有一个简单的C++类:

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

    void sleep()
    {
        sleep(x);
    }

private:
    int x;
};

Widget::sleep块,因此我想释放GIL,以便Python可以做一些其他事情,因此我将Widget::sleep包装在如下函数中:

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

为完整起见,绑定代码如下所示:

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

表达式中的所有参与者的ref计数是否在表达式的持续时间内递增? 当在C.foo中使用时,c.x的唯一引用是c,在t.start()后面的行可以方便地删除它。 由于pyWidgetSleep释放了GIL,del c.x可能会减少对Widget实例的最后一个引用,从而导致未定义的行为。你知道吗


我无法在我的机器上进行此中断,这似乎是一个很好的迹象,表明它如我所期望的那样工作,但引用计数没有记录到如此清晰的程度 (或者,至少,我似乎找不到它)。CPython的相关部分似乎是PyEval_EvalCodeEx,看起来它将Py_INCREF应用于所有参数 参与了一个函数调用,但我可能对那个完全不感兴趣。你知道吗


Tags: importselffoodefsleepwidgetclassstate
1条回答
网友
1楼 · 发布于 2024-10-06 12:14:07

这个问题的答案是:是的,它是安全的。这是在Python中如何调用成员函数的结果。考虑一下Widget是否是用Python实现的:

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

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

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

相关问题 更多 >