Я пытаюсь создать простую фабричную функцию для обертывания Python функций в QThread
, чтобы предотвратить блокировку основного потока приложения при выполнении длительно выполняющихся некритических операций в фоновом режиме (например, кэширования данных).
Я попытался подписаться на популярную запись в блоге , в которой описывается фактическое предполагаемое использование QThread
без подкласса и отмены run
. Я искал решения своих проблем более половины дня и, кажется, не могу заставить ничего работать, что бы я ни пытался и как. У меня есть искушение сделать это «неправильным» способом и создать подкласс QThread
. Код для оболочки следующий.
from qtpy.QtCore import Slot, Signal, QThread, QObject
class Worker(QObject):
finished = Signal()
def __init__(self, target, *args, parent=None, **kwargs):
super().__init__(parent)
self.__target = target
self.__args = args
self.__kwargs = kwargs
def run(self):
self.__target(*self.__args, **self.__kwargs)
self.finished.emit()
def create_thread(target, *args, parent=None, **kwargs):
thread = QThread(parent)
worker = Worker(target, *args, **kwargs, parent=parent)
worker.moveToThread(thread)
thread.started.connect(worker.run)
worker.finished.connect(thread.quit)
worker.finished.connect(worker.deleteLater)
thread.finished.connect(thread.deleteLater)
return thread
При использовании функции make_thread
с передачей target
без установки parent
экземпляру QMainWindow
функция target
выполняется и блоков, но затем происходит сбой после выдачи finished
. Любые вызовы print
в функции target
также не выводят ничего на stdout
.
Process finished with exit code -1073741819 (0xC0000005)
Если установлено parent
, запускается target
и выводит на stdout
но также блокирует основной поток и не позволяет виджетам становиться видимыми до тех пор, пока не будет выпущено finished
, оставляя главное окно зависшим и пустым на время.
Пример интерфейса, который я использую, просто имеет QLabel
для пример виджета, который предназначен для немедленного показа, пока target
выполняется в фоновом режиме. Он не отображается, пока не завершится target
, и только если указано parent
из QThread
. В противном случае программа просто вылетает (ровно через пять секунд, как показано в примере ниже). Ни один из этих кодов не работает ни в PySide2
, ни в PyQt5
.
import sys
import time
from qtpy.QtWidgets import QApplication, QMainWindow, QLabel, QWidget, QVBoxLayout
import modpack_builder.gui.helpers as helpers
class ExampleMainWindow(QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)
self.setCentralWidget(QWidget(self))
self.centralWidget().setLayout(QVBoxLayout(self.centralWidget()))
self.label = QLabel("If you see this immediately, the thread did not block.", self.centralWidget())
self.centralWidget().layout().addWidget(self.label)
self.test_thread = helpers.create_thread(self.long_running_task)
self.test_thread.start()
@staticmethod
def long_running_task():
print("Task started.")
time.sleep(5)
print("Task finished.")
if __name__ == "__main__":
app = QApplication(list())
window = ExampleMainWindow()
window.show()
sys.exit(app.exec_())
Если в этом вопросе слишком много тегов или они избыточны, сообщите мне. Я никогда не могу сказать наверняка, какие использовать.