python - 将多个 Python 子解释器嵌入到 C 程序中
问题描述
我正在编写一个生成多个 C 线程的 C 程序,每个线程有一个 Python 子解释器。子解释器不共享任何可变的 Python 变量,它们彼此隔离。(它们确实对从 C 程序中的 main() 函数公开的公共 PyObject(不可变)具有只读访问权限)。
这在 Python 3.7 或 3.8 中是否可能,而无需在子解释器之间共享 GIL?
这是我一直在尝试的伪代码:
void *spawnInterpreter(void* p) {
…
PyThreadState* save_tstate = PyThreadState_Swap(NULL);
PyThreadState* tstate = Py_NewInterpreter();
PyThreadState_Swap(save_tstate);
//do some Python work (with variables that are NOT shared with other thread’s sub-interpreter
PyRun_SimpleString( . . .);
. . .
}
int main() {
...
pthread_create(&thread1, NULL, spawnInterpreter, “in1”);
pthread_create(&thread2, NULL, spawnInterpreter, "in2");
...
}
我可以让它在 3.6 中工作(无需获取 GIL 或PyThreadState
在 C 线程中管理),但在 Python 3.7 中我得到:
[New Thread 0x7ffff5f78700 (LWP 16392)]
Fatal Python error: drop_gil: GIL is not locked
解决方案
不幸的是,子解释器在 3.7 和 3.8 中仍然共享 GIL。这是我个人正在努力改变的事情。请参阅PEP 554和我的多核 Python 项目。下周我还将在 PyCon 上发表演讲,详细介绍该主题。
我一直希望在 Python 3.8 中实现这一点,但在这一点上,它看起来更有可能在 3.9 中实现。主要挑战是 C-API 和 CPython 运行时不是线程安全的。虽然大多数 C-API 和运行时都可以切换到使用 per-interpreter GIL,但在这种情况下其他事情必须改变:
- 一些进程全局资源必须在没有 GIL 的情况下更仔细地管理(例如环境变量、文件句柄)
- 存在解释器必须继续共享的全局运行时状态,因此仍然必须通过全局锁来保护很多内容(尽管不需要阻塞 Python 字节码 eval 循环)
- 一些全局运行时状态需要下移到每个解释器状态(例如 GC、内存分配器、警告)
- 对象将需要严格按解释器进行(目前),因此 C-API 必须严格禁止对象跨越解释器边界
- 非特定于解释器上下文的 C-API 部分必须更改为不再需要持有 GIL
这个问题很容易解决,但是在处理这些关键代码时需要时间来采取必要的谨慎措施。因此可能的目标是 3.9。
无论如何,我很感谢你在这里发帖。我的大部分努力都集中在对 Python 代码的影响上,而不是 C-API(例如嵌入器)。因此,有关我的项目如何通过 C-API 使用子解释器的反馈非常有帮助。例如,您提醒我的一件事是,通过 C-API 创建子解释器与 PEP 554 中的等效项略有不同。这需要更仔细地考虑。此外,PEP 554 几乎没有在 C-API 中公开任何添加内容。这可能没问题,但在短期内与来自 C-API 的渠道进行交互可能很有价值。
推荐阅读
- java - 如何在lowdb Json中实现where条件?
- javascript - 尝试向元素添加 css background-image 属性,但它不断在我的 url 中添加空格
- swift - 无法解决一对多关系
- ios - 在 react-native 网络错误上使用 Axios 时出错
- android - 带有 ViewPager 偏移的 Android 动画
- c# - 获取注册为“每个请求”的对象的新(单独)实例
- python - 如何在不使用后端函数的情况下在 keras 中编写自定义函数?
- django - 如何使用 CBV 将 PermissionDenied Redirect 提升到另一个页面?
- javascript - javascript箭头函数()=>()是什么意思?
- node.js - Dialogflow 网络钩子(Google 上的操作)。我是否应该使用 RichResponse?