记一次嵌入式Python+SWIG入门开发 (二)
1、Python 子解释器
一般情况下我们程序中只使用一个全局的 Python 解释器就够用了,但是在某些情况下,比如我们想要隔离两个线程的环境,例如加载的模块表(sys.modules
)和模块搜索路径(sys.path
)等,就需要用到子解释器了。Python 子解释器顾名思义就是在全局解释器下,再创见出一个或多个解释器,解释器之间可相互切换调用,但都是运行在全局解释器中。具体细节可查看 Python/C API 官方文档。
-
创建子解释器
我们可以通过函数 Py_NewInterPreter 创建出一个子解释器,但是在创建之前需要通过函数 PyGILState_Ensure 获取 GIL (Global Interpreter Lock,即全局解释器锁)。#include "Python.h" class PythonEnv { public: PythonEnv(); ~PythonEnv(); private: void test(); PyThreadState *m_pState; PyThreadState *m_pThread; }; PythonEnv::PythonEnv() { PyGILState_STATE state = PyGILState_Ensure(); # 当前线程保存 GIL,并能够调用任意 Python 代码 PyThreadState *save = PyEval_SaveThread(); # 释放 GIL ,并将当前线程状态重置为 NULL, 返回先前的线程状态 PyEval_RestoreThread(save); # 获取 GIL ,并将线程状态设置为 save PyThreadState *m_pState = Py_NewInterpreter(); # 创建子解释器 PyThreadState *m_pThread = PyThreadState_New(m_pState->interp); # 在子解释器中创建新的线程 PyThreadState_Swap(save); # 将当前线程状态设置为 save save = PyEval_SaveThread(); # 释放 GIL ,并将当前线程状态重制为 NULL, 返回先前的线程状态 PyEval_RestoreThread(save); # 获取 GIL ,并将线程状态设置为 save PyGILState_Release(state); # 释放以前获取的所有资源 }
-
在子解释器中调用 Python
创建完子解释器后,我们就可以在子解释器中调用 Python 代码了。但是需要注意的是,由于子解释器是多线程的,所以需要获取 GIL 后才能调用,此处我们用函数 PyEval_AcquireThread 获取 GIL,不可使用 PyGILState_Ensureÿ