How to use QThread correctly in pyqt with moveToThread()?(如何通过 moveToThread() 在 pyqt 中正确使用 QThread?)
问题描述
我阅读了这篇文章 如何真正真正地使用 QThreads;完整的解释,它说代替子类 qthread,并重新实现 run(),应该使用 moveToThread 使用 moveToThread(QThread*) 将 QObject 推送到 QThread 实例上
i read this article How To Really, Truly Use QThreads; The Full Explanation, it says instead of subclass qthread, and reimplement run(), one should use moveToThread to push a QObject onto QThread instance using moveToThread(QThread*)
这是 c++ 示例,但我不知道如何将其转换为 python 代码.
here is the c++ example, but i don't know how to convert it to python code.
class Worker : public QObject
{
Q_OBJECT
QThread workerThread;
public slots:
void doWork(const QString ¶meter) {
// ...
emit resultReady(result);
}
signals:
void resultReady(const QString &result);
};
class Controller : public QObject
{
Q_OBJECT
QThread workerThread;
public:
Controller() {
Worker *worker = new Worker;
worker->moveToThread(&workerThread);
connect(workerThread, SIGNAL(finished()), worker, SLOT(deleteLater()));
connect(this, SIGNAL(operate(QString)), worker, SLOT(doWork(QString)));
connect(worker, SIGNAL(resultReady(QString)), this, SLOT(handleResults(QString)));
workerThread.start();
}
~Controller() {
workerThread.quit();
workerThread.wait();
}
public slots:
void handleResults(const QString &);
signals:
void operate(const QString &);
};
QThread* thread = new QThread;
Worker* worker = new Worker();
worker->moveToThread(thread);
connect(worker, SIGNAL(error(QString)), this, SLOT(errorString(QString)));
connect(thread, SIGNAL(started()), worker, SLOT(process()));
connect(worker, SIGNAL(finished()), thread, SLOT(quit()));
connect(worker, SIGNAL(finished()), worker, SLOT(deleteLater()));
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
thread->start();
我一直在使用这种方法来生成一个 qthread ,但正如您所看到的,它使用的是不推荐的方式.我如何重写它以使用首选方法?
i've been using this method to generate a qthread , but as you can see, it's using the not recommended way. how can i re-write it to use the preferred method ?
class GenericThread(QThread):
def __init__(self, function, *args, **kwargs):
QThread.__init__(self)
# super(GenericThread, self).__init__()
self.function = function
self.args = args
self.kwargs = kwargs
def __del__(self):
self.wait()
def run(self, *args):
self.function(*self.args, **self.kwargs)
两年后...我试过 qris 的代码,它在不同的线程中工作
edit: two years later ... I tried qris' code, it works and in different thread
import sys
import time
from PyQt4 import QtCore, QtGui
from PyQt4.QtCore import pyqtSignal, pyqtSlot
import threading
def logthread(caller):
print('%-25s: %s, %s,' % (caller, threading.current_thread().name,
threading.current_thread().ident))
class MyApp(QtGui.QWidget):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
self.setGeometry(300, 300, 280, 600)
self.setWindowTitle('using threads')
self.layout = QtGui.QVBoxLayout(self)
self.testButton = QtGui.QPushButton("QThread")
self.testButton.released.connect(self.test)
self.listwidget = QtGui.QListWidget(self)
self.layout.addWidget(self.testButton)
self.layout.addWidget(self.listwidget)
self.threadPool = []
logthread('mainwin.__init__')
def add(self, text):
""" Add item to list widget """
logthread('mainwin.add')
self.listwidget.addItem(text)
self.listwidget.sortItems()
def addBatch(self, text="test", iters=6, delay=0.3):
""" Add several items to list widget """
logthread('mainwin.addBatch')
for i in range(iters):
time.sleep(delay) # artificial time delay
self.add(text+" "+str(i))
def test(self):
my_thread = QtCore.QThread()
my_thread.start()
# This causes my_worker.run() to eventually execute in my_thread:
my_worker = GenericWorker(self.addBatch)
my_worker.moveToThread(my_thread)
my_worker.start.emit("hello")
# my_worker.finished.connect(self.xxx)
self.threadPool.append(my_thread)
self.my_worker = my_worker
class GenericWorker(QtCore.QObject):
start = pyqtSignal(str)
finished = pyqtSignal()
def __init__(self, function, *args, **kwargs):
super(GenericWorker, self).__init__()
logthread('GenericWorker.__init__')
self.function = function
self.args = args
self.kwargs = kwargs
self.start.connect(self.run)
@pyqtSlot()
def run(self, *args, **kwargs):
logthread('GenericWorker.run')
self.function(*self.args, **self.kwargs)
self.finished.emit()
# run
app = QtGui.QApplication(sys.argv)
test = MyApp()
test.show()
app.exec_()
输出为:
mainwin.__init__ : MainThread, 140221684574016,
GenericWorker.__init__ : MainThread, 140221684574016,
GenericWorker.run : Dummy-1, 140221265458944,
mainwin.addBatch : Dummy-1, 140221265458944,
mainwin.add : Dummy-1, 140221265458944,
mainwin.add : Dummy-1, 140221265458944,
mainwin.add : Dummy-1, 140221265458944,
mainwin.add : Dummy-1, 140221265458944,
mainwin.add : Dummy-1, 140221265458944,
mainwin.add : Dummy-1, 140221265458944,
推荐答案
QThread 中默认的 run() 实现会为你运行一个事件循环,相当于:
The default run() implementation in QThread runs an event loop for you, the equivalent of:
class GenericThread(QThread):
def run(self, *args):
self.exec_()
事件循环的重要之处在于它允许线程拥有的对象在其插槽上接收事件,这些事件将在该线程中执行.这些对象只是 QObjects,而不是 QThreads.
The important thing about an event loop is that it allows objects owned by the thread to receive events on their slots, which will be executed in that thread. Those objects are just QObjects, not QThreads.
重要说明:QThread 对象不属于自己的线程!它是在主线程上创建的并存在于那里.除了 run 方法,它的所有代码都在主线程中执行.
Important note: the QThread object is not owned by its own thread! It was created on the main thread and lives there. Apart from its run method, all of its code executes in the main thread.
所以你应该能够做到这一点:
So you should be able to do this:
class GenericWorker(QObject):
def __init__(self, function, *args, **kwargs):
super(GenericWorker, self).__init__()
self.function = function
self.args = args
self.kwargs = kwargs
self.start.connect(self.run)
start = pyqtSignal(str)
@pyqtSlot
def run(self, some_string_arg):
self.function(*self.args, **self.kwargs)
my_thread = QThread()
my_thread.start()
# This causes my_worker.run() to eventually execute in my_thread:
my_worker = GenericWorker(...)
my_worker.moveToThread(my_thread)
my_worker.start.emit("hello")
另外,仔细想想当前被丢弃的 self.function
的结果会发生什么.您可以在 GenericWorker
上声明另一个信号,它接收结果,并让 run()
方法在完成后发出该信号,将结果传递给它.
Also, think carefully about what happens with the result of self.function
, which is currently discarded. You could declare another signal on GenericWorker
, which receives the result, and have the run()
method emit that signal when it's done, passing the result to it.
一旦你掌握了它的窍门并意识到你不应该也不应该继承 QThread,生活就会变得更加简单和容易.简单地说,永远不要在 QThread 中工作.您几乎不需要覆盖 run.对于大多数用例,将 QObject 与 QThread 建立适当的关联并使用 QT 的信号/插槽创建了一种非常强大的多线程编程方式.请注意不要让您推送到工作线程的 QObjects 闲逛...
Once you get the hang of it and realize you don't and shouldn't subclass QThread, life becomes a lot more straightforward and easier. Simply put, never do work in QThread. You should almost never need to override run. For most use cases, setting up proper associations with a QObject to a QThread and using QT's signals/slots creates an extremely powerful way to do multithreaded programming. Just be careful not to let the QObjects you've pushed to your worker threads hang around...
http://ilearnstuff.blogspot.co.uk/2012/09/qthread-best-practices-when-qthread.html
这篇关于如何通过 moveToThread() 在 pyqt 中正确使用 QThread?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!
本文标题为:如何通过 moveToThread() 在 pyqt 中正确使用 QThread?
基础教程推荐
- 使用PyInstaller后在Windows中打开可执行文件时出错 2022-01-01
- 在 Python 中,如果我在一个“with"中返回.块,文件还会关闭吗? 2022-01-01
- Python kivy 入口点 inflateRest2 无法定位 libpng16-16.dll 2022-01-01
- 如何在海运重新绘制中自定义标题和y标签 2022-01-01
- 何时使用 os.name、sys.platform 或 platform.system? 2022-01-01
- 线程时出现 msgbox 错误,GUI 块 2022-01-01
- 筛选NumPy数组 2022-01-01
- 用于分类数据的跳跃记号标签 2022-01-01
- 如何让 python 脚本监听来自另一个脚本的输入 2022-01-01
- Dask.array.套用_沿_轴:由于额外的元素([1]),使用dask.array的每一行作为另一个函数的输入失败 2022-01-01