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 (и я считаю, что сигнальный слот является хорошим способом связи), я буду использовать подход «рабочий объект» .
2,Пример кода из официальных документов
В официальных документах Qt5 по QThreads (см. http://doc.qt.io/qt-5/qthread.html),, вы можете найти образец кода. Я попытался перевести его на Python:
(См. Этот вопрос stackoverflow, чтобы увидеть более подробную информацию об этом переводе: QThreads в Pyqt5: это правильный перевод C ++ на Python официальных документов QThread? )
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. Мой вопрос: можно создавать объекты вконструктор рабочего?
Из великой статьи г-жи Майи Пош (https://mayaposch.wordpress.com/2011/11/01/how-to-really-truly-use-qthreads-the-full-explanation/), Я цитирую:
Кстати, одна чрезвычайно важная вещь, на которую следует обратить внимание:что вы НИКОГДА не должны выделять объекты кучи (используя new) в конструкторе класса QObject, так как это распределение затем выполняется в главном потоке, а не в новом экземпляре 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-битная