【发布时间】:2018-05-25 19:48:09
【问题描述】:
1。一些背景资料
关于如何实例化和使用 QThread 的官方文档可以在这里找到:http://doc.qt.io/qt-5/qthread.html
文档描述了两种基本方法:(1) 工作对象方法和 (2) QThread 子类方法。
> 下面的文章解释了为什么在使用第二种方法时需要小心: https://mayaposch.wordpress.com/2011/11/01/how-to-really-truly-use-qthreads-the-full-explanation/
> 以下文章解释了为什么这两种方法各有千秋: https://woboq.com/blog/qthread-you-were-not-doing-so-wrong.html
我引用:
根据经验:
如果你真的不需要线程中的事件循环,你应该子类化。 如果您需要一个事件循环并在线程中处理信号和槽,您可能不需要子类化。
由于我确实需要在 QApplication 线程和新 QThread 之间进行某种通信(而且我相信信号槽是一种很好的通信方式),我将使用 worker-object 方法 .
2。来自官方文档的示例代码
在 QThreads 上的官方 Qt5 文档(请参阅 http://doc.qt.io/qt-5/qthread.html)上,您可以找到示例代码。我已努力将其翻译成 Python:
(请参阅此 stackoverflow 问题以了解有关该翻译的更多详细信息:QThreads in Pyqt5: is this the correct C++ to Python translation of the official QThread docs?)
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
class Worker(QObject):
resultReady = pyqtSignal(str)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# Note: this constructor is empty now.
# But would it be okay to instantiate new
# objects here, and use them in doWork(..)?
# A more general question: is it okay if
# doWork(..) accesses variables that were
# created in another thread (perhaps the
# main QApplication thread)?
@pyqtSlot(str)
def doWork(self, param):
result = "hello world"
print("foo bar")
# ...here is the expensive or blocking operation... #
self.resultReady.emit(result)
class Controller(QObject):
operate = pyqtSignal(str)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# 1. Create 'workerThread' and 'worker' objects
# ----------------------------------------------
self.workerThread = QThread()
self.worker = Worker()
self.worker.moveToThread(self.workerThread)
# 2. Connect all relevant signals
# --------------------------------
self.workerThread.finished.connect(self.worker.deleteLater)
self.operate.connect(self.worker.doWork)
self.worker.resultReady.connect(self.handleResults)
# 3. Start the thread
# --------------------
self.workerThread.start()
def __del__(self):
self.workerThread.quit()
self.workerThread.wait()
@pyqtSlot(str)
def handleResults(self, param):
print(param)
global app
app.exit()
if __name__ == '__main__':
app = QCoreApplication([])
controller = Controller()
controller.operate.emit("foo")
sys.exit(app.exec_())
如您所见,Worker 类的构造函数是空的。这将我们带到下一段。
3。我的问题:可以在worker的构造函数中创建对象吗?
来自Mss. 的精彩文章。 Maya Posch (https://mayaposch.wordpress.com/2011/11/01/how-to-really-truly-use-qthreads-the-full-explanation/),我引用:
顺便说一句,这里要注意的一件非常重要的事情是,你永远不应该在 QObject 类的构造函数中分配堆对象(使用 new),因为这个分配是在主线程上执行的,而不是在新的 QThread 实例上,这意味着新创建的对象然后由主线程拥有,而不是 QThread 实例。这将使您的代码无法正常工作。相反,在这种情况下,在诸如 process() 之类的主函数槽中分配此类资源,因为当调用该对象时,该对象将位于新线程实例上,因此它将拥有该资源。
[Maya Posch -如何真正真正地使用qthreads,完整解释]
本文是为 C++ 软件编写的。
这句话仍然适用于 Python 应用程序吗?也就是说,在Worker类的构造函数中实例化对象可以吗?
更一般地说,我可以问:如果doWork(..) 函数访问在另一个线程(可能是主 QApplication 线程)中实例化的变量,是否可以?
特此提供我当前的系统设置:
> Qt5 (QT_VERSION_STR = 5.10.1)
> PyQt5 (PYQT_VERSION_STR = 5.10.1)
> Python 3.6.3
> Windows 10,64 位
【问题讨论】:
-
言归正传,一个对象属于创建它的线程,在Qt的情况下,它避免了属于一个线程的对象在另一个线程中使用,所以正确的事情不是在构造函数中创建它,或者执行它然后使用 moveToThread() 将其移动到新线程。与其看语言,不如看 Qt 提供的基本概念。
-
另外,它提供的代码与您当前的问题无关,您在构造函数中没有看到任何对象的创建,并不表示您有问题。
-
如果您只依赖语言,将代码从一种语言翻译成另一种语言没有多大意义,因为像 Qt 这样的库提供了其他限制。
-
嗨@eyllanesc,你是对的。
Worker类的构造函数当前为空。我在代码中添加了注释以澄清:-) -
嗨@eyllanesc,您对翻译问题是正确的。请查看我的另一个 StackOverflow 问题,该问题侧重于翻译本身:stackoverflow.com/questions/50531797/…。随意张贴你的评论:-)
标签: python python-3.x qt5 pyqt5 qthread