Одновременное выполнение двух потоков

У меня есть программа которая должна выполнять ряд функций одновременно в разных потоках, но при одновременном запуске этих функций программа крашится.

Написал простой пример как я запускаю эти функции:

from PyQt5.QtCore import QCoreApplication, QObject, QRunnable, QThread, QThreadPool, pyqtSignal, pyqtSlot
from PyQt5 import Qt
import sys
import time

class MainWindow(Qt.QWidget):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)

        layout = Qt.QVBoxLayout(self)
        self.lblA = Qt.QLabel("Итог выполения первого потока")
        layout.addWidget(self.lblA)
        self.btnA = Qt.QPushButton("Запустить первый поток")
        layout.addWidget(self.btnA)
        self.lblB = Qt.QLabel("Итог выполения второго потока")
        layout.addWidget(self.lblB)
        self.btnB = Qt.QPushButton("Запустить второй поток")
        layout.addWidget(self.btnB)

        self.init_ui()

    def init_ui(self):
        self.btnA.clicked.connect(self.thread_one)
        self.btnB.clicked.connect(self.thread_two)

    def thread_one(self):
        self.object_thread = MultiOne()
        self.multithreading = QThread()
        self.object_thread.moveToThread(self.multithreading)
        self.multithreading.started.connect(self.object_thread.example_function)
        self.object_thread.finished.connect(self.multithreading.quit)
        self.object_thread.finished.connect(self.fill_lblA)

        self.multithreading.start()

    def thread_two(self):
        self.object_thread = MultiTwo()
        self.multithreading = QThread()
        self.object_thread.moveToThread(self.multithreading)
        self.multithreading.started.connect(self.object_thread.example_function)
        self.object_thread.finished.connect(self.multithreading.quit)
        self.object_thread.finished.connect(self.fill_lblB)

        self.multithreading.start()

    def fill_lblA(self, text):
        self.lblA.setText(text)

    def fill_lblB(self, text):
        self.lblB.setText(text)


class MultiOne(QObject):
    finished = pyqtSignal(str)

    def __init__(self):
        super(MultiOne, self).__init__()

    def example_function(self):
        i = 0
        while i < 10:
            i += 1
            time.sleep(0.5)

        self.finished.emit(f'Ура! Первая функция отработала')


class MultiTwo(QObject):
    finished = pyqtSignal(str)

    def __init__(self):
        super(MultiTwo, self).__init__()

    def example_function(self):
        i = 0
        while i < 5:
            i += 1
            time.sleep(0.5)

        self.finished.emit(f'Ура! Вторая функция отработала')


if __name__ == '__main__':
    app = Qt.QApplication([])
    application = MainWindow()
    application.show()
    sys.exit(app.exec())

В моем примере если нажать первую или вторую кнопку и дождаться выполнения, то все работает корректно, но если нажать сразу обе кнопки, то программа крашится.

Я понимаю что скорее всего пытаюсь в уже запущенный поток поместить другой объект и из-за это происходит ошибка. Как правильно запустить второй поток для выполнения второй функции? Я понимаю что есть способ создать класс с наследованием от QThread, переопределить функцию run и сделать это для каждой функции, но есть ли способы с наследованием от QObject и помещением объекта в поток?

В оригинале программы в потоках выполняется обработка SQL и Postman запросов.


Ответы (1 шт):

Автор решения: gil9red

Нехорошо, что вы используете одну переменную для хранения разных объектов:

    def thread_one(self):
        self.object_thread = MultiOne()
        self.multithreading = QThread()
    
    ...

    def thread_two(self):
        self.object_thread = MultiTwo()
        self.multithreading = QThread()

Представим ситуацию:

  • Вы создали объект MultiOne и QThread при запуске первой кнопки
  • Объекты живут и работают
  • После вы запустили вторую кнопку и переписали переменные, а это значит, что на эти объекты пропали ссылки, тогда их нужно удалить
  • Но логика запущена, а объектов нет - ошибка

Поэтому, вижу такие решения:

1. Разные переменные для объектов

    def thread_one(self):
        self.object_thread_1 = MultiOne()
        self.multithreading_1 = QThread()
        self.object_thread_1.moveToThread(self.multithreading_1)
        self.multithreading_1.started.connect(self.object_thread_1.example_function)
        self.object_thread_1.finished.connect(self.multithreading_1.quit)
        self.object_thread_1.finished.connect(self.fill_lblA)

        self.multithreading_1.start()

    def thread_two(self):
        self.object_thread_2 = MultiTwo()
        self.multithreading_2 = QThread()
        self.object_thread_2.moveToThread(self.multithreading_2)
        self.multithreading_2.started.connect(self.object_thread_2.example_function)
        self.object_thread_2.finished.connect(self.multithreading_2.quit)
        self.object_thread_2.finished.connect(self.fill_lblB)

        self.multithreading_2.start()

2. Добавление ссылки на объект, путем указания родителя потока

В обе функции укажите:

self.multithreading = QThread(self)
→ Ссылка