多线程提升 Python C++ PySide 中的代码
Multithreading Boost Python C++ Code in PySide
我有用Boost Python包装的c ++代码。 这个想法是,我创建了一个共享对象,我的python GUI可以使用它来实例化包装c ++功能的变量。
c++ 代码做了一些提升,我希望能够使包装的对象并发运行,以便 GUI 不会阻塞。
我编译了一个用CMake包装的Boost Python共享对象,如下所示:
find_package(Boost COMPONENTS system thread python REQUIRED)
find_package(PythonLibs REQUIRED)
include_directories(${Boost_INCLUDE_DIRS})
include_directories(${PYTHON_INCLUDE_DIRS})
link_directories(${Boost_LIBRARY_DIRS})
link_directories(${PYTHON_LIBRARIES})
set(Boost_USE_MULTITHREADED ON)
add_library(mynewlibinpython SHARED src/boost_python_wrapper_code.cpp)
target_link_libraries(mynewlibinpython ${Boost_LIBRARIES} ${PYTHON_LIBRARIES} mylibincpp)
我可以很好地在 python 中实例化对象,但它会导致 GUI 阻塞。 这是我的python代码的通用片段:
from mynewlibinpython import *
class CppWrapper(QtCore.QObject):
def __init__(self):
super(CppWrapper,self).__init__()
#some more initialization...
@QtCore.Slot()
def heavy_lifting_cpp_invocation():
#constructor that takes a long time to complete
self.cpp_object = CppObject()
在一个具有成员函数的对象中,当我按下 GUI 中的按钮时会触发该函数:
class GuiObjectWithUnimportantName:
def __init__(self):
#inititalization
self.cpp_thread = QThread()
self.cpp_wrapper = CppWrapper()
def function_triggered_by_button_press(self):
self.cpp_wrapper.moveToThread(self.cpp_thread)
self.cpp_thread.started.connect(self.cpp_wrapper.heavy_lifting_cpp_invocation)
print "starting thread"
self.cpp_thread.start()
print "Thread started"
因此,cpp 代码将开始做它的事情,我基本上也会立即从两个 print
语句("start thread"和"Thread started")获得输出。
但是 GUI 被冻结了。 这与python GIL有什么关系吗?我尝试将这些宏添加到boost_python_wrapper_code.cpp
中并重新编译,但它导致 python GUI 在启动后立即出现段错误。
是的,我相信您的问题与 GIL 有关。下面是一个可能发生的事情的简单示例:
from PyQt4 import QtCore, QtGui
import time
class Window(QtGui.QDialog):
def __init__(self):
super(Window, self).__init__()
self.resize(200,100)
layout = QtGui.QVBoxLayout(self)
layout.addWidget(QtGui.QLineEdit())
self.button1 = QtGui.QPushButton("Sleep")
self.button1.clicked.connect(self.go_safe)
layout.addWidget(self.button1)
self.button2 = QtGui.QPushButton("Crunch")
self.button2.clicked.connect(self.go_GIL_buster)
layout.addWidget(self.button2)
def go_safe(self):
t = QtCore.QThread(self)
heavy = Heavy()
heavy.moveToThread(t)
t.started.connect(heavy.safe)
print "starting thread"
t.start()
print "thread started"
self.t1 = t
self.heavy1 = heavy
def go_GIL_buster(self):
t = QtCore.QThread(self)
heavy = Heavy()
heavy.moveToThread(t)
t.started.connect(heavy.GIL_buster)
print "starting thread"
t.start()
print "thread started"
self.t2 = t
self.heavy2 = heavy
class Heavy(QtCore.QObject):
def safe(self):
print "Sleeping"
time.sleep(10)
print "Done"
def GIL_buster(self):
print "Crunching numbers"
x = 2
y = 500000000
foo = x**y
print "Done"
if __name__ == "__main__":
app = QtGui.QApplication([])
win = Window()
win.show()
win.raise_()
app.exec_()
当您单击第一个按钮时,线程将休眠 10 秒钟,您会注意到您仍然可以在文本字段中键入内容。睡眠释放 GIL,以便主线程可以继续工作。
单击第二个按钮时,线程将执行大量操作。这将在整个过程中获取 GIL,并且 GUI 将锁定,直到完成。
如果你的 boost 扩展没有以任何方式对 python 对象做任何事情,我认为你可以发布 GIL 用于其操作。然后它不会阻止 GUI。如果你正在对 python 对象进行繁重的操作,那么你在这里可能会遇到问题。
有一个关于创建基于范围的 GIL 发布类的提示,您可以在任何函数中使用该类在该函数的持续时间内释放 GIL(当帮助程序实例被销毁时)
class ScopedGILRelease
{
// C & D ----------------------------
public:
inline ScopedGILRelease()
{
m_thread_state = PyEval_SaveThread();
}
inline ~ScopedGILRelease()
{
PyEval_RestoreThread(m_thread_state);
m_thread_state = NULL;
}
private:
PyThreadState * m_thread_state;
};
并使用它...
int foo_wrapper(int x)
{
ScopedGILRelease scoped;
return foo(x);
}
其他人在此存储库中有更多使用此提示的示例:https://bitbucket.org/wwitzel3/code/src/tip/nogil/nogil.cpp
- C++我的数学有什么问题,为什么我的代码不能正确循环
- 代码在main()中运行,但在函数中出现错误
- 在VS代码中交叉编译Windows与Linux上的MinGW的SDL程序
- 编译包含字符串的代码时遇到问题
- 我在c++代码中生成了一个运行时#3异常
- 如何在linux终端中同时编译和运行c++代码
- 为cl.exe(Visual Studio代码)指定命令行C++版本
- 在Linux for Windows上编译C++代码时出错
- 我的字符计数代码计算错误.为什么
- 孤立代码块在结构中引发异常
- 在编译C++代码(具有dlib和opencv)到WASM时面临问题
- 为什么我的C#代码在调用回C++COM直到Task时会暂停.等待/线程.加入
- 处理小于cpu数据总线的数据类型.(c++转换为机器代码)
- 此代码是否违反一个定义规则
- 为什么我的代码在输出中增加了93天
- 我的简单if-else语句是如何无法访问的代码
- 使用动态分配的数组会导致代码分析发出虚假的C6386缓冲区溢出警告
- 为什么在这个代码结束循环中没有得到结束
- 在c代码之间共享数据的最佳方式
- 多线程提升 Python C++ PySide 中的代码