[英]Why is the work being done by my QThread starving the main thread?
這是我基於QThread編寫的可愛線程。 您會注意到它有一個事件隊列。 4秒后,將觸發一個事件並在doWork
中進行一些工作。 doWork
應該在所有打印之間休眠,並給其他線程運行的機會。 可以說,所有的doWork
打印和睡眠時間都足夠長,以至於另一個線程確實應該花一些時間來執行。
from PySide.QtCore import *
from PySide.QtGui import *
class DoStuffPeriodically(QThread):
def __init__(self):
super(DoStuffPeriodically, self).__init__()
def doWork(self):
#... do work, post signal to consumer
print "Start work"
for i in range(0,100):
print "work %i" % i
QThread.msleep(10)
print "Done work"
return
def run(self):
""" Setup "pullFiles" to be called once a second"""
self.timer= QTimer()
self.timer.setSingleShot(True)
self.timer.timeout.connect(self.doWork)
self.timer.start(4000)
self.exec_()
這是我用來控制線程的頂級QT小部件。 它基本上只是一個啟動/停止線程的按鈕。
class Widg(QWidget):
def __init__(self):
super(Widg, self).__init__()
self.thread = DoStuffPeriodically()
self.startStopButton = QPushButton()
hBoxLayout = QHBoxLayout()
hBoxLayout.addWidget(self.startStopButton)
self.startStopButton.pressed.connect(self.startStopThread)
self.setLayout(hBoxLayout)
self.threadRunning = False
def startStopThread(self):
if self.threadRunning:
print "Stopping..."
self.thread.exit(0)
self.threadRunning = False
print "Stopped"
else:
print "Starting..."
self.thread.start()
self.threadRunning = True
print "Started"
if __name__ == "__main__":
from sys import argv
qApp = QApplication(argv)
widg = Widg()
widg.show()
qApp.exec_()
如果單擊startStopButton,我希望看到線程開始打印
Starting... Started... Start Work work 0 work 1 ... work 99 Done Work
但是我要做的是能夠在執行工作時停止線程。 我期待一些類似的東西
Starting... Started... Start Work work 0 work 1 ... work N Stopping... work 99 Done Work Stopped...
相反, 工作線程似乎正在阻止主線程執行? 我必須等待工作完成后才能單擊startStopButton,這給了我
Starting... Started... Start Work work 0 work 1 ... work 99 Done Work Stopping... Stopped...
doWork
運行多長時間都沒有關系。 我已經將其循環了10000次。 它似乎從來沒有花時間返回主線程,並且小部件沒有響應。 我是否正在做一些阻止實際線程實際工作的事情?
(我正在使用python 2.7和pyside 1.10。)
如果我修改run
以直接執行工作,而不是基於QTimer
則線程似乎可以正常工作。 即更改run
為:
def run(self):
self.doWork()
return
這不能解決我的問題,因為我想使用事件隊列運行。 因此,我懷疑這是QTimer
信號與錯誤線程相關聯的某種信號/插槽問題。
注意,在工作完成之前,我不會遇到該exit
或quit
塊。 我只是在經歷線程根本不起作用。 即主窗口被阻止,我什至不能單擊按鈕甚至發起退出線程
問題在於QThread
方法正在完成工作。 QThread
的線程相似性始終是創建 QThread的線程 。 因此,該信號告訴QThread
的所屬線程執行doWork
-在這種情況下為主線程。 因此,即使在此QThread中定義了doWork
,該工作仍由主線程完成。 我知道那種心神扭曲。 為了解釋,讓我首先引用文檔
QThread對象位於另一個線程中,即創建該線程的那個線程。
因此,當此信號/插槽連接已建立時
self.timer.timeout.connect(self.doWork)
它,默認情況下是一個AutoConnection :
(默認值)如果信號是從與接收對象不同的線程發出的,則該信號將排隊,表現為Qt :: QueuedConnection。 否則,將以Qt :: DirectConnection的形式直接調用該插槽。 連接類型是在發出信號時確定的。
信號的源是我的QThread,因為QTimer是在run
方法中創建的,但目標是主線程。 它正在主線程的事件隊列中排隊! 解決方案是創建第二個工作線程QObject,它具有當前線程的親和力:
class Worker(QObject):
def __init__(self, parent):
super(Worker, self).__init__(parent=parent)
def doWork(self):
#... do work, post signal to consumer
print "Start work"
for i in range(0,1000):
print "work %i" % i
QThread.msleep(100)
print "Done work"
return
然后運行成為:
def run(self):
""" Setup "pullFiles" to be called once a second"""
print "Running..."
self.worker = Worker(parent=None) #affinity = this thread
self.timer= QTimer() #affinity = this thread
print self.timer.thread()
self.timer.setSingleShot(True)
self.timer.timeout.connect(self.worker.doWork)
self.timer.start(4000)
self.exec_()
print "Exec_ done"
這可行。 信號的源和目的地都在一個線程中,並且不會遍歷到主線程。 瞧!
從QThread :: exit()文檔中:
Tells the thread's event loop to exit with a return code.
您的doWork
是事件循環中的單個事件。 事件循環稱為您的事件,因此等待它完成。 exit
是另一個事件,它已排入事件循環並等待doWork
完成。 msleep
有助於提高GUI的響應速度(使它有時間重新繪制和執行按鈕處理程序),但實際上並不能使exit
事件以某種方式潛行。
如果您希望doWork
隨時可中斷,則必須更改邏輯。 使計時器更頻繁地觸發並且僅增加一。 然后退出即可在此之間的任何時間行動。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.