QThreads в Pyqt5: нормально ли создавать новые объекты в конструкторе рабочего класса? - PullRequest
0 голосов
/ 25 мая 2018

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-битная

1 Ответ

0 голосов
/ 25 мая 2018

В этом ответе я рассортирую все задачи моих комментариев.

Много раз он путает концепцию потока с QThread, если документы пересмотрены:

Класс QThread предоставляет независимый от платформы способ управлять потоками

Он не является оберткой собственных потоков, но в процессе чтения он является обработчиком.

Метод run() - это начало потока, также обозначенное документами :

Начальная точка для потока ...

Когда вы используете moveToThread(), он изменяет сродство потока объекта и его дочерних элементов, это относится к QObject s.

Для того, что указывает ваша цитата, вы должны избегать того, чтобыQObject создается в конструкторе, если вы используете его только в doWork(), кроме того, это подразумевает, что он является членом класса, который часто не нужен.Если вы делаете, решение заключается в том, что вы используете moveToThread(), в случае, если это дочерний элемент Worker, очевидно, нет необходимости.


Qt, чтобы избежать этих проблем с доступом к объектам, созданным в другом потоке Iрекомендуем использовать сигналы или QMetaObject, которые являются поточно-ориентированными.

Наконец, использование QThread является очень низким уровнем, для выполнения задач многопоточности Qt предлагает другие технологии с QThreadPool с QRunnable, избегаяэти проблемы.В c ++ также есть QtConcurrent, но он недоступен в PyQt

...