簡體   English   中英

為什么我的QThread所做的工作使主線程餓了?

[英]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信號與錯誤線程相關聯的某種信號/插槽問題。

注意,在工作完成之前,我不會遇到該exitquit塊。 我只是在經歷線程根本不起作用。 即主窗口被阻止,我什至不能單擊按鈕甚至發起退出線程

問題在於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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM