将多个Python子解释器嵌入到C程序中

时间:2018-12-29 01:03:07

标签: python c cpython python-c-api

我正在编写一个生成多个C线程的C程序,每个线程一个Python子解释器。子解释器不共享任何可变的Python变量,它们彼此隔离。 (它们确实对从C程序的main()函数公开的公共PyObject(不可变)具有只读访问权限。)

在Python 3.7或3.8中是否可以实现,而无需在子解释器之间共享GIL?

这是我一直在尝试的伪代码:

library(tidyverse)
output <- weird_data %>%
  separate(API, into = c("well", "act"), sep = "-", remove = F) %>%
  group_by(well) %>%
  fill(Month) %>%
  ungroup() %>%
  select(-well, -act)

all.equal(output, desired_output)
#[1] TRUE

我可以使它在3.6中工作(无需获取GIL或在C线程中管理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"); ... } ),但是在Python 3.7中,我得到了:

PyThreadState

1 个答案:

答案 0 :(得分:3)

不幸的是,子解释器仍然在3.7和3.8中共享GIL。这是我个人正在努力进行的工作。请参见PEP 554my multi-core Python project。我还将在下周提供a talk at PyCon,以详细介绍该主题。

我一直希望能够在Python 3.8中实现这一点,但目前看来3.9的可能性更大。主要挑战是C-API和CPython运行时不是线程安全的。虽然大多数C-API和运行时都可以切换为使用按解释器的GIL,但在这种情况下,其他事情将不得不更改:

  • 必须在没有GIL的情况下更仔细地管理某些进程全局资源(例如env vars,文件句柄)
  • 解释器必须继续共享全局运行时状态,因此仍然必须由全局锁来保护很多(尽管 不需要锁定Python字节码eval循环)
  • 某些全局运行时状态需要下移到每个解释器状态(例如GC,内存分配器,警告)
  • 现在必须严格按照解释器来定义对象,因此C-API必须严格禁止对象越过解释器边界
  • 非特定于解释器上下文的C-API部分必须更改为不再需要持有GIL

这个问题很容易解决,但是在处理此类关键代码时需要花费一些时间来应用必要的注意事项。因此,可能的目标是3.9。


无论如何,我很感谢您在这里发布。我的大部分努力都集中在对Python代码的影响上,而不是C-API(例如embedders)上。因此,有关我的项目如何通过C-API与子解释器的使用相关的反馈非常有用。例如,您让我想起的一件事是,通过C-API创建子解释器与PEP 554中的等效方法略有不同。需要更仔细地考虑这一点。同样,PEP 554在C-API中几乎没有公开任何添加。可能没关系,但是从短期来看,与C-API中的渠道进行交互可能很有价值。