In addition to the GUI, I need several background threads running along with the GUI, I looked in the direction of threading, but as I understood there GIL does not allow threads to work in parallel. QThread works the same? How can I run 2-3 parallel threads that won't wait for each other (if they don't use the same data)? Can an example of sending data to the GUI? You are welcome...

1 answer 1

From the point of view of "parallelism" between the Thread and QTread classes QTread really is no difference, except that the QTread instance is able to send messages to the main window through the slot mechanism. In GUI, individual threads are created as a rule so that the interface does not hang. It is rarely necessary to really count a lot and do it in separate processes. If you work with a network or files - here is an example on PySide2

 from PySide2.QtUiTools import QUiLoader from PySide2.QtWidgets import QApplication, QProgressBar, QTableWidgetItem, QHeaderView from PySide2.QtCore import Qt, QFile, QObject, Slot, Signal, QThread from PySide2.QtGui import QIcon, QStandardItemModel, QStandardItem class LoaderDataChunk(QThread): valueChanged = Signal([int, int], name='val') def __init__(self, id, q, parent=None): QThread.__init__(self, parent) self.id = id self.q = q def run(self): # что-то делаем... # посылаем сигнал для разморозки интерфейса главного приложения self.valueChanged.emit(self.id, i) # если работаем через очередь - основной поток может безопасно подождать окончания self.q.task_done() class Downloader(QObject): def __init__(self, ui_file, parent=None): super(Downloader, self).__init__() ui_file = QFile(filename) ui_file.open(QFile.ReadOnly) loader = QUiLoader() self.window = loader.load(ui_file) ui_file.close() self.window.setWindowIcon(QIcon(iconfile)) def loadData(self): chunks = [] # наша огромная задача self.q = Queue() for i, chunk in enumerate(chunks): self.q.put(chunk) pg = QProgressBar() pg.setValue(0) loader = LoaderDataChunk(i, self.q self) loader.valueChanged.connect(self.showProgress) loader.start() # морозим интерфейс до выполнения задачи self.window.frame.setEnabled(False) self.window.menu.setEnabled(False) thread = threading.Thread(target=self.waitResult) thread.start() @Slot(int, int) def showProgress(self, id, value): self.progress_list[id].setValue(value) def waitResult(self): print('start waiting...') self.q.join() self.window.frame.setEnabled(True) self.window.menu.setEnabled(True) 

You can do it differently - not to create a lot of threads, but to work asynchronously. Then you need only one thread, to request a new eventloop in it, and in this loop you will have to turn all operations. Again, this second thread must inherit from QTread