pybind11 多线程调用pyton解释器

python因为GIL锁的存在,所以在多线程的访问c++中的python解释器时,会出现各种坑

出于业务需求,需要使用python解释器处理前端发过来的python代码,最开始的处理方法是构造了一个单例的python解释器类(我司大佬设计的),在构造函数中调用 Py_Initialize()在析构函数中调用Py_Finalize()(也是大佬用这种方式解决GIL问题的),同时使用try catch捕捉py::error_already_set,在catch中先后调用Py_Finalize()和Py_Initialize()去刷一下状态(这里是我这个菜狗写的)。

但是,在使用过程中发现,如果一直执行正确的python代码,服务就不会有问题,python抛出异常也可以被正确捕捉。但是即使进行了Py_Finalize()和Py_Initialize(),在下一次请求调用时,再去import我们自己封的类,就会提示某个成员已经被注册过了,(也可能在import的时候线程阻塞,此时如果还有请求进来,进程就会段错误,服务500

根据 pybind11官方文档

#include <pybind11/embed.h> // everything needed for embedding
namespace py = pybind11;

int main() {
    py::scoped_interpreter guard{}; // start the interpreter and keep it alive

    py::print("Hello, World!"); // use the Python API
}

发现官方使用了一个叫scoped_interpreter 的东西,这个可以初始化解释器,直到它的生命周期结束,但是是一个单线程的程序,我在rest接口的回调函数里使用了这个方法,希望每次请求都可以初始化一个python解释器,请求完毕再释放掉。但是在第二次请求时会抛runtime error

最后根据 这篇文章
在主进程里初始化解释器,并且释放GIL锁

int main(int argc, char* argv[]) {
    pybind11::scoped_interpreter python;
    pybind11::gil_scoped_release release; // add this to release the GIL
    ...
    return 0;
}

然后在我的回调函数中

void callBack(const string &code, string &errorMsg) {
    std::mutex pythonMutex;
    std::lock_guard<std::mutex> lock(pythonMutex);   //线程锁
    py::gil_scoped_acquire acquire;                  //申请GIL锁
    py::exec("globals().clear()");                   //因为所有用户共用一个解释器,所以清一下变量
    try {
       py::exec(code);                               //执行用户提交的代码
    } catch (const py::error_already_set &e) {
        errorMsg += e.what();
    }
}

就好了

  • 7
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值