PDA

View Full Version : Yet another "keeping the GUI responsive"



dubbaluga
8th August 2011, 21:45
Hi all,

I'm heaving problems with offloading some CPU-intensive calculations to a separate thread. My GUI's response is too slow, sometimes it takes several seconds to repaint/refresh. I have a dual-core CPU with recent amd64-Linux running.

Maybe there is some misunderstanding: so far I thought it's only about starting the background thread and let it go. I have been reading Keeping the GUI responsive (http://www.qtcentre.org/wiki/index.php?title=Keeping_the_GUI_Responsive) but it has not really help me yet. As you can see in the code (below), my thread does not do anything useful except from eating loads of CPU-cycles. :)

Here is what I've tried so far:

Invoking QtCore.QCoreApplication.processEvents() (http://www.pyside.org/docs/pyside/PySide/QtCore/QCoreApplication.html#PySide.QtCore.PySide.QtCore. QCoreApplication.processEvents) (line 20, 23-26)
Setting thread priority (line 58)
Instantiating a worker-object on the stack of the thread and invoking the worker's method using QtCore.QTimer.singleShot() (http://www.pyside.org/docs/pyside/PySide/QtCore/QTimer.html#PySide.QtCore.PySide.QtCore.QTimer.sin gleShot) to make sure processed data only lives on the thread's stack


The only thing that helped me a little bit was setting the thread priority. Is there anything I can do to let my program have a better response time? I'm especially interested in solutions that work with third-party code, meaning invoking CPU-intensive methods from external libraries which I cannot extend with Qt-related functionality.

Thank you for your support in advance,
Rainer



import sys
from PySide import QtGui, QtCore, QtUiTools

# Import the compiled UI module
from customwidget import Ui_customWidget


class CCalculation(QtCore.QThread):

sProgress = QtCore.Signal(int)
sFinished = QtCore.Signal()

def __init__(self, pData):
super(CCalculation, self).__init__()
self.mData = pData

def run(self):
lCnt = 0
lTotal = len(self.mData)
# lLast = datetime.datetime.now()
for lNum in self.mData:
self.mData[lCnt] = lNum ** 2
# lNow = datetime.datetime.now()
# if (lNow - lLast) > datetime.timedelta(0, 0, 100000):
# lLast = lNow
# QtCore.QCoreApplication.processEvents()
if 100 * lCnt / lTotal % 10 == 0:
self.sProgress.emit(100 * lCnt / lTotal)
lCnt = 0
self.sFinished.emit()

class CMain:

sNumElements = 200000
sAccessElement = 22

def __init__(self):
# GUI code
self.mApp = QtGui.QApplication(sys.argv)
self.mWindow = QtGui.QMainWindow()
self.mWidget = QtGui.QWidget()
self.mFactory = Ui_customWidget()
self.mFactory.setupUi(self.mWidget)
self.mWindow.setCentralWidget(self.mWidget)

# Threading
self.mData = range(CMain.sNumElements)
self.mThread = CCalculation(self.mData)
self.mThreadRunning = QtCore.QMutex()

# wire signals and slots
self.mThread.sProgress.connect(self.mFactory.progr essBar.setValue)
self.mThread.sFinished.connect(self.threadFinished )
self.mFactory.processButton.clicked.connect(self.s tartThread)

def startThread(self):
if self.mThreadRunning.tryLock() == True:
#self.mThread.start(QtCore.QThread.IdlePriority)
self.mThread.start()

def threadFinished(self):
self.mFactory.textEdit.setText(str(self.mData[CMain.sAccessElement]))
self.mThreadRunning.unlock()

def run(self):
self.mWindow.show()
lReturn = self.mApp.exec_()
self.mThread.quit()
self.mThread.wait()
sys.exit(lReturn)


if __name__ == "__main__":
lMain = CMain()
lMain.run()

wysota
9th August 2011, 07:29
Does not emitting the progress signal bring back responsiveness of the UI?