在C++代码中释放Python GIL

7 投票
3 回答
3846 浏览
提问于 2025-04-15 15:06

我有一个用C++写的库,我通过SWIG把它包装起来,然后在Python中使用。通常这个库里有一个类和几个方法。问题是,调用这些方法可能会耗费很多时间——它们可能会让我的应用程序卡住(因为在调用这些方法时,GIL没有被释放)。所以我想问的是:

有没有什么简单的方法可以在调用这些方法时释放GIL?

(我明白如果我使用的是C库,我可以通过一些额外的C代码来包装它,但这里我使用的是C++和类。)

3 个回答

0

你可以用跟C语言一样的API调用,没什么不同。只需要包含“python.h”这个文件,然后调用合适的函数就行。

另外,看看SWIG有没有什么类型映射之类的东西,可以指示某个特定的函数不需要持有GIL(全局解释器锁)。

9

真正的问题是,SWIG的文档写得不太好(我看到有人建议用更新日志来查找信息;)

好吧,我发现我可以在SWIG中使用内联函数,并用宏来释放或获取全局解释器锁(GIL),它看起来是这样的:

%inline %{
    void wrappedFunction(OriginalObject *o, <parameters>) {
    Py_BEGIN_ALLOW_THREADS
    o->originalFunction(<parameters>);
    Py_END_ALLOW_THREADS
}
%}

这个函数在原来的C++代码中并不存在,但在Python模块中可以找到。这几乎正是我想要的。(我希望的其实是像Python装饰器那样包装原始方法)

9

虽然我对SWIG一点都不了解,但我还是试着回答一下 :)

可以使用类似下面的代码来释放或获取GIL:

class GILReleaser {
    GILReleaser() : save(PyEval_SaveThread()) {}

    ~GILReleaser() {
        PyEval_RestoreThread(save);
    }

    PyThreadState* save;
};

然后在你选择的代码块中,利用RAII来释放或获取GIL:

{
    GILReleaser releaser;
    // ... Do stuff ...
}

撰写回答