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

问题描述 投票:4回答:1

我正在编写一个产生多个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或在C线程中管理PyThreadState),但在Python 3.7中我得到:

[New Thread 0x7ffff5f78700 (LWP 16392)]
Fatal Python error: drop_gil: GIL is not locked
python c cpython python-c-api
1个回答
3
投票

遗憾的是,subinterpreters仍然在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(例如嵌入器)。因此,关于我的项目如何通过C-API与子解释器的使用相关的反馈非常有用。例如,您提醒我的一件事是,通过C-API创建子解释器与PEP 554中的等效解释略有不同。需要更仔细地考虑。此外,PEP 554几乎没有在C-API中公开其添加内容。这可能没问题,但是与C-API的渠道进行交互可能在短期内很有价值。

© www.soinside.com 2019 - 2024. All rights reserved.