0

I have replaced my original question to add a working example of the code. Again, this is Python 3.7 x64 under Windows 10 x64.

Alright. Here is a minimal example using pyQT5 and both multi-threading and multi-processing.

from concurrent import futures
from PyQt5 import QtWidgets, uic
from PyQt5.QtWidgets import QApplication
from PyQt5.QtCore import pyqtSlot
from sys import argv

class GuiShell(QtWidgets.QMainWindow):

    totalSum=0

    def __init__(self):
        super(GuiShell, self).__init__()
        uic.loadUi("MyUI.ui", self)        
        self.btnStartThreads.clicked.connect(self.onbtStartThreadsClicked)  
        self.btnStartProcesses.clicked.connect(self.onbtStartProcessesClicked)  

    pyqtSlot()
    def onbtStartThreadsClicked(self):
        self.txtList.clear()
        self.multiThread()

    pyqtSlot()
    def onbtStartProcessesClicked(self):
        self.txtList.clear()
        self.multiProcess()

    def doSomething(self, num):
        return self.totalSum + num

    # Calculate sum of numbers from 1 to 10
    def multiThread(self):
        self.totalSum=0
        with futures.ThreadPoolExecutor() as executor:  
            threadList=[]
            for num in range(11):
                thread= executor.submit(self.doSomething, num)
                threadList.append(thread)

            for finishedThread in futures.as_completed(threadList):
                self.totalSum+= finishedThread.result()

        self.txtList.append("Total sum= {}".format(self.totalSum))

    def multiProcess(self):
        with futures.ProcessPoolExecutor() as executor: 
            self.totalSum=0
            threadList=[]
            for num in range(11):
                thread= executor.submit(self.doSomething, num)
                threadList.append(thread)

            for finishedThread in futures.as_completed(threadList):
                self.totalSum+= finishedThread.result()

        self.txtList.append("Total sum= {}".format(self.totalSum))

#========== MAIN ==============================
if __name__ == '__main__':
    app= QtWidgets.QApplication(argv)
    window = GuiShell()
    window.show()
    app.exec_()

The interface has a text edit (QTextEdit) and 2 push buttons. One button executes the sum of all numbers from 1 to 10 using threads (single core), and the other using processes (multi-core). Both have EXACTLY the same code, except for the Thread or Process declaration lines.

The thread version works and the processes one crashes the program. I have tested the same code without pyQt5, and it works in both cases. ProcessPoolExecutor seems to have an issue with pyQt5.

  • Alright. Here is a minimal example using pyQT5 and both multi-threading and multi-orocessing. – Ken Kawashima Jan 30 '20 at 18:27
  • No, it is not a MRE. An MRE would allow me to make a copy-paste of the code without adding or removing code and should reproduce your problem but clearly it is not. – eyllanesc Jan 30 '20 at 18:29
  • 1
    I have replaced my original question with a full code example illustrating the issue. – Ken Kawashima Jan 30 '20 at 18:46
  • Ok, the answer to the problem is that whatever is called from executor.submit() for multi-core processing cannot be in the same scope of the class. It can be for multi-threading, but not for multi-processing. If it is, the call will create multiple instances of the entire class, instead of just the function call. So the solution is to move the called function to OUTSIDE the class scope. It can be anywhere that is not part of the QAppication scope. This way, only that code will be instantiated and executed in multiple cores at the same time. That resolves the issue. – Ken Kawashima Jan 30 '20 at 20:27
  • I take back what I said above. That only works if there is only a single class in the entire program. My program has several other classes instantiated from the main class, meaning that simply moving the called function outside the class, it is STILL inside the same module, which is instantiated from the same hierarchy that leads to QApplication. This causes multi-core threading to open a new instance of the entire program (QApplication) with every new thread it starts, which crashes it. Therefore that is not a viable solution unless you have only a single class. – Ken Kawashima Jan 30 '20 at 21:40

0 Answers0