使用 Python 和 C api 进行多线程
Posted
技术标签:
【中文标题】使用 Python 和 C api 进行多线程【英文标题】:Multithreading with Python and C api 【发布时间】:2015-04-12 22:10:08 【问题描述】:我有一个 C++ 程序,它使用 C api 来使用我的 Python 库。 Python 库和 C++ 代码都是多线程的。
特别是,C++ 程序的一个线程实例化了一个继承自threading.Thread
的 Python 对象。我需要我的所有 C++ 线程能够调用该对象上的方法。
从我的第一次尝试(我天真地只是从主线程实例化对象,然后等待一段时间,然后调用该方法)我注意到与刚刚创建的对象关联的 Python 线程的执行一旦停止执行回到 C++ 程序。
如果继续使用 Python 执行(例如,如果我调用 PyRun_SimpleString("time.sleep(5)");
),则 Python 线程会在后台继续执行,一切正常,直到等待结束并返回 C++。
我显然做错了什么。我应该怎么做才能使我的 C++ 和 Python 成为多线程的 both 并能够很好地相互协作?我之前没有该领域的经验,所以请不要假设任何事情!
【问题讨论】:
【参考方案1】:执行您要执行的操作的正确步骤顺序是:
在主线程中:
-
使用
Py_Initialize*
初始化Python。
使用 PyEval_InitThreads()
初始化 Python 线程支持。
启动 C++ 线程。
此时,主线程仍然持有 GIL。
在 C++ 线程中:-
使用
PyGILState_Ensure()
获取 GIL。
创建一个新的 Python 线程对象并启动它。
使用 PyGILState_Release()
发布 GIL。
睡觉,做一些有用的事情或退出线程。
由于主线程持有 GIL,该线程将等待获取 GIL。如果主线程调用 Python API,它可能会不时释放 GIL,让 Python 线程执行一段时间。
回到主线程:-
释放 GIL,使线程能够使用
PyEval_SaveThread()
运行
在尝试使用其他 Python 调用之前,请使用 PyEval_RestoreThread()
重新获取 GIL
我怀疑你错过了最后一步——在主线程中释放 GIL,让 Python 线程执行。
我在this link 有一个小而完整的示例。
【讨论】:
【参考方案2】:当你从python的threading.Thread
回调时,你可能没有解锁Global Interpreter Lock。
好吧,如果你使用的是裸 python 的 C API,你有 some documentation here,关于如何释放/获取 GIL。但是在使用 C++ 时,我必须警告你,它可能会在你的 C++ 代码中抛出任何异常时崩溃。 See here.
一般来说,任何运行时间过长的 C++ 函数都应该解锁 GIL 并锁定,只要它再次使用 C Python API。
【讨论】:
很抱歉,我似乎没有正确理解这一点。这是我所做的:1)PyGILState_STATE gstate; gstate = PyGILState_Ensure();
2)创建从threading.Thread
继承的 python 对象 3)PyGILState_Release(gstate);
4)休眠几秒钟(在 C++ 中)在运行函数中,对象应该打印一次在一段时间内,但它显然只在最初的几毫秒内这样做。我在做什么错..?以上是关于使用 Python 和 C api 进行多线程的主要内容,如果未能解决你的问题,请参考以下文章
写出java多线程程序设计中常用类及方法名,并分别说明它们的作用。