Как заставить QThreads работать в консольной программе PySide?

Я пытаюсь научиться использовать потоки в программе на Python. Я использую PySide и QThreads, так как я собираюсь впоследствии реализовать графический интерфейс с PySide.

Я понял основную концепцию потоков, по крайней мере, я так думаю. Но я все еще путаюсь с циклами событий. И я думаю, что это проблема с моим заявлением.

Вот пример приложения, которое я не могу заставить работать должным образом. В моем основном классе у меня есть несколько рабочих потоков, и я хочу, чтобы они сообщали о своем прогрессе в основной основной класс. Но основная программа не печатает сообщения о прогрессе в реальном времени.

Как я мог заставить это работать?

from PySide import QtCore
import time, sys

class MyWorkerThread(QtCore.QThread):
    message = QtCore.Signal(str)

    def __init__(self, id, parent=None):
        super(MyWorkerThread, self).__init__(parent)
        self.id = id

    def run(self):
        for i in range(10):
            self.message.emit("%d: %d" % (self.id, i))
            time.sleep(0.2)

class MainProgram():
    def __init__(self, parent=None):
        self.threads = []

        self.addWorker(MyWorkerThread(1))
        self.addWorker(MyWorkerThread(2))

    def addWorker(self, worker):
        worker.message.connect(self.printMessage, QtCore.Qt.QueuedConnection)
        self.threads.append(worker)

    def startWorkers(self):
        for worker in self.threads:
            worker.start()
            worker.wait()
        self.workersFinished()

    def workersFinished(self):
        QtCore.QCoreApplication.instance().quit()

    @QtCore.Slot(str)
    def printMessage(self, text):
        sys.stdout.write(text+'\n')
        sys.stdout.flush()

if __name__ == '__main__':
    app = QtCore.QCoreApplication(sys.argv)
    m = MainProgram()
    m.startWorkers()
    sys.exit(app.exec_())

1 ответ

Решение

worker.wait() это проблема. Этот вызов блокирует основной поток (в данном случае один запущенный цикл обработки событий), пока рабочий не завершит свою работу.

Вот немного измененная версия (я прокомментировал свои изменения):

from PySide import QtCore
import time, sys

class MyWorkerThread(QtCore.QThread):
    message = QtCore.Signal(str)

    def __init__(self, id, parent=None):
        super(MyWorkerThread, self).__init__(parent)
        self.id = id

    def run(self):
        for i in range(10):
            self.message.emit("%d: %d" % (self.id, i))
            time.sleep(0.2)

class MainProgram():
    def __init__(self, parent=None):
        self.threads = []

        self.addWorker(MyWorkerThread(1))
        self.addWorker(MyWorkerThread(2))

    def addWorker(self, worker):
        worker.message.connect(self.printMessage, QtCore.Qt.QueuedConnection)
        # connect the finished signal to method so that we are notified
        worker.finished.connect(self.workersFinished)
        self.threads.append(worker)

    def startWorkers(self):
        for worker in self.threads:
            worker.start()
            # no wait, no finished. you start the threads and leave.

    def workersFinished(self):
        if all(worker.isFinished() for worker in self.threads):
            # wait until all the threads finished
            QtCore.QCoreApplication.instance().quit()

    @QtCore.Slot(str)
    def printMessage(self, text):
        sys.stdout.write(text+'\n')
        sys.stdout.flush()

if __name__ == '__main__':
    app = QtCore.QCoreApplication(sys.argv)
    m = MainProgram()
    m.startWorkers()
    sys.exit(app.exec_())
Другие вопросы по тегам