Jon*_*rin 10 python gil pybind11
PyGILState_Ensure()pybind11 是否以某种方式神奇地完成了和的工作PyGILState_Release()?如果没有,我该怎么做?
关于使用 pybind11 将 python 函数作为回调传递给 C++有 很多 问题,但我还没有找到一个解释如何使用 pybind11 的 GIL 的问题。
\n文档中关于 GIL 的说明非常清楚:
\n\n\n[...] 但是,当从 C 创建线程时(例如由具有自己的线程管理的第三方库),它们不\xe2\x80\x99t 保存 GIL,也不存在它们的线程状态结构。
\n如果您需要从这些线程调用Python代码(通常这将是上述第三方库提供的回调API的一部分),您必须首先通过创建线程状态数据结构向解释器注册这些线程,然后获取GIL,最后存储它们的线程状态指针,然后才能开始使用 Python/C API。
\n
我可以轻松绑定一个需要回调的 C++ 函数:
\npy::class_<SomeApi> some_api(m, "SomeApi"); \nsome_api\n .def(py::init<>())\n .def("mode", &SomeApi::subscribe_mode, "Subscribe to \'mode\' updates.");\nRun Code Online (Sandbox Code Playgroud)\n相应的 C++ 函数类似于:
\nvoid subscribe_mode(const std::function<void(Mode mode)>& mode_callback);\nRun Code Online (Sandbox Code Playgroud)\n但是因为 pybind11 无法了解我的 C++ 实现中发生的线程,所以我认为它无法为我处理 GIL。因此,如果mode_callback由从 C++ 创建的线程调用,这是否意味着我应该为每个调用编写一个包装SomeApi::subscribe_mode器?PyGILState_Ensure()PyGILState_Release()
这个答案似乎做了类似的事情,但仍然略有不同:调用回调时不是“获取 GIL”,而是在启动/停止线程时“释放 GIL”。我仍然想知道是否存在类似的东西py::call_guard<py::gil_scoped_acquire>()可以完全满足我(相信我)的需要,即用PyGILState_Ensure()and包装我的回调PyGILState_Release()。
pybind11 尝试做正确的事情,当 pybind11 知道它正在调用 python 函数时,或者在通过 pybind11 从 python 调用的 C++ 代码中,GIL 将被保留。使用 pybind11 时,唯一需要显式获取 GIL 的情况是,当您编写访问 python 的 C++ 代码并将从其他 C++ 代码调用时,或者您已显式删除 GIL 时。
包装器总是在调用函数时std::function通过获取GIL ,因此无论从哪个线程调用它,您的Python回调将始终在持有GIL的情况下被调用。gil_scoped_acquire
如果gil_scoped_acquire从当前没有与其关联的 GIL 线程状态的线程调用,那么它将创建一个新的线程状态。作为副作用,如果线程中没有其他东西获取线程状态并增加引用计数,那么一旦您的函数退出,GIL 将由 的析构函数释放gil_scoped_acquire,然后它将删除与该线程关联的线程状态。
如果您只从另一个线程调用该函数一次,那么这不是问题。如果您经常调用回调,它将大量创建/删除线程状态,这可能对性能不利。最好在线程启动时创建线程状态(或者更简单,从 Python 启动线程并从 python 调用 C++ 代码)。
| 归档时间: |
|
| 查看次数: |
1378 次 |
| 最近记录: |