在多线程C应用程序中嵌入蟒蛇(Embedding python in multithreaded C

2019-06-24 12:53发布

我嵌入在多线程C应用程序的Python解释器,我为我应该用什么API来保证线程安全有点困惑。

从我收集的,嵌入蟒蛇时,它是到嵌入照顾GIL锁调用任何其他Python C API调用之前。 这是通过这些功能来完成:

gstate = PyGILState_Ensure();
// do some python api calls, run python scripts
PyGILState_Release(gstate);

但仅此似乎并不足够。 我还有随机崩溃,因为似乎提供了Python API的互斥它不会。

阅读一些文档我还添加了后:

PyEval_InitThreads();

在调用之后Py_IsInitialized()但是这也正是混淆的部分来了。 该文档指出此函数:

初始化并获得全局解释锁

这表明,当这个函数返回时,GIL应该被锁定,应该得到某种解锁。 但在实践中,这似乎并不需要。 有了这条线来代替我的多线程完美工作和互斥被保持PyGILState_Ensure/Release功能。
当我尝试添加PyEval_ReleaseLock()PyEval_ReleaseLock()的应用程序死锁很快在随后的调用PyImport_ExecCodeModule()

那我在这里失踪?

Answer 1:

我有完全相同的问题,现在是利用解决PyEval_SaveThread()后立即PyEval_InitThreads()因为你上面建议。 然而,我的实际问题是,我用PyEval_InitThreads()PyInitialise()然后造成PyGILState_Ensure()以阻止来自不同的,随后本地线程调用时。 总之,这就是我现在做的事:

  1. 有全局变量:

     static int gil_init = 0; 
  2. 从主线程加载本地C扩展,并启动Python解释器:

     Py_Initialize() 
  3. 从多个其他线程我的应用程序同时使得很多电话到Python / C API的:

     if (!gil_init) { gil_init = 1; PyEval_InitThreads(); PyEval_SaveThread(); } state = PyGILState_Ensure(); // Call Python/C API functions... PyGILState_Release(state); 
  4. 从主线程停止Python解释器

     Py_Finalize() 

我已经尝试了所有其他解决方案,无论是造成随机的Python sigfaults或死锁/使用阻塞PyGILState_Ensure()

Python文档确实应该对这个更加清晰,至少两个嵌入和扩展使用案例提供了一个例子。



Answer 2:

最后我想通了。

PyEval_InitThreads();

你需要调用

PyEval_SaveThread();

同时适当释放GIL主线程。



Answer 3:

具有多线程应用程序的ç试图从多个线程进行通信,以单一的CPython实例的多个线程的Python看起来危险的我。

只要只有一种C线与Python通信,你不应该担心锁定即使Python应用程序是多线程。 如果需要多个线程蟒可以设置应用了这种方式,并有多个C线程通过与一个C线程养殖场出来到多线程的Python队列通信。

这可能为你工作的替代方法是有多个实例CPython的一个关于C线程需要它(的Python程序之间的通信过程中应该可以通过C程序)。

另一种选择可能的Stackless的Python解释器。 这摒弃了GIL,但我不知道您遇到了其他问题,它绑定到多个线程。 无堆栈是一个简易替换为我(单线程)C应用。



文章来源: Embedding python in multithreaded C application