这个问题

pybind11是否神奇地完成了PyGILState_Ensure()PyGILState_Release()的工作?如果没有,我该怎么做?

更多详细信息

关于使用pybind11将python函数作为回调传递给C++的问题,但我还没有找到一个可以解释GIL与pybind11一起使用的问题.

documentation人对GIL非常清楚:

[...] 然而,当线程是从C创建的(例如由具有自己的线程管理的第三方库创建)时,它们不持有GIL,也没有线程状态 struct .

如果需要从这些线程调用Python代码(通常这是上述第三方库提供的回调API的一部分),则必须首先通过创建线程状态数据 struct 向解释器注册这些线程,然后获取GIL,最后存储其线程状态指针,然后才能开始使用Python/C API.

我可以轻松绑定接受回调的C++函数:

py::class_<SomeApi> some_api(m, "SomeApi"); 
some_api
    .def(py::init<>())
    .def("mode", &SomeApi::subscribe_mode, "Subscribe to 'mode' updates.");

With the corresponding C++ function being something like:

void subscribe_mode(const std::function<void(Mode mode)>& mode_callback);

但是由于pybind11不知道我的C++实现中发生的线程,我想它不能为我处理GIL.因此,如果mode_callback由C++创建的线程调用,这是否意味着我应该为SomeApi::subscribe_mode编写一个包装器,每个调用使用PyGILState_Ensure()PyGILState_Release()

This answer似乎在做类似的事情,但仍然略有不同:在调用回调时,它似乎不是"接受GIL",而是在启动/停止线程时"释放GIL".我仍然想知道是否有像py::call_guard<py::gil_scoped_acquire>()这样的东西可以完全满足我(相信我)的需要,即用PyGILState_Ensure()PyGILState_Release()包装我的回调.

推荐答案

一般来说

pybind11try 做正确的事情,当pybind11知道它正在调用python函数时,或者在通过pybind11从python调用的C++代码中,GIL将被保留.当使用pybind11时,您需要显式获取GIL的唯一时间是当您编写访问python的C++代码并将从其他C++代码调用时,或者如果您显式删除了GIL.

std::函数包装器

std::function的包装器总是通过gil_scoped_acquire when the function is called获取GIL,因此python回调总是在GIL保持的情况下调用,无论从哪个线程调用.

如果从当前没有关联GIL线程状态的线程调用gil_scoped_acquire,则它将为create a new thread state.作为一个副作用,如果线程中没有任何其他内容获取线程状态并增加引用计数,那么一旦函数退出,GIL将由gil_scoped_acquire的析构函数释放,然后由it will delete the thread state associated with that thread的析构函数释放.

如果您只从另一个线程调用该函数一次,这不是问题.如果您经常调用回调,它会大量创建/删除线程状态,这可能对性能没有好处.最好在线程启动时创建线程状态(或者更简单的是,从Python启动线程并从Python调用C++代码).

Python相关问答推荐

下三角形掩码与seaborn clustermap bug

语法错误:文档. evaluate:表达式不是合法表达式

Python Mercury离线安装

Pandas在rame中在组内洗牌行,保持相对组的顺序不变,

裁剪数字.nd数组引发-ValueError:无法将空图像写入JPEG

如何使用加速广播主进程张量?

函数()参数';代码';必须是代码而不是字符串

大Pandas 中的群体交叉融合

如何让PYTHON上的Selify连接到现有的Firefox实例-我无法连接到Marionette端口

为什么fizzbuzz在两个数字的条件出现在一个数字的条件之后时不起作用?

如何更改GEKKO变量在解算为稳定状态后的MV状态?

查找一个数据帧中另一个数据帧的值的索引

使用极轴 Select 一系列柱

如何只保留Pandas DataFrame尾部的第一个重复行?

为什么REGISTER_NEXT_STEP_HANDLER不立即调用函数并等待另一条消息

如何根据预定义的模板重新排序YAML键并维护注释?

向NumPy数组添加字符串

带参数约束的类型提示函数*args->;tuple[*args]

基于行值迭代/填充列

如何将按钮移动到按钮在GRadio中使用或更改的框之前?