微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何推迟 QRunnable 的执行,直到发出来自前一个的信号

如何解决如何推迟 QRunnable 的执行,直到发出来自前一个的信号

为了不冻结 PyQT GUI,我使用 QRunnable(在后台执行的函数)和 QThreadPool。我有三个函数,其中一个需要前两个函数的结果才能运行,我正在努力确保在前两个函数返回各自的结果后开始执行第三个函数

QThreadPool 的类定义如下:

class Worker(QtCore.QRunnable):
'''
Worker thread

Inherits from QRunnable to handler worker thread setup,signals and wrap-up.

:param callback: The function callback to run on this worker thread. Supplied args and
                 kwargs will be passed through to the runner.
:type callback: function
:param args: Arguments to pass to the callback function
:param kwargs: Keywords to pass to the callback function

'''

def __init__(self,fn,*args,**kwargs):
    super(Worker,self).__init__()

    # Store constructor arguments (re-used for processing)
    self.running = None
    self.fn = fn
    self.args = args
    self.kwargs = kwargs
    self.signals = WorkerSignals()

    # Add the callback to our kwargs
    self.kwargs['callback_progress'] = self.signals.progress
    self.kwargs['callback_data'] = self.signals.data

# @Slot()
def run(self):
    '''
    Initialise the runner function with passed args,kwargs.
    '''

    # Retrieve args/kwargs here; and fire processing using them
    try:
        self.signals.started.emit()
        self.result = self.fn(
            *self.args,**self.kwargs
        )
    except:
        traceback.print_exc()
        exctype,value = sys.exc_info()[:2]
        self.signals.error.emit((exctype,value,traceback.format_exc()))
    else:
        self.signals.result.emit(self.result)  # Return the result of the processing
    finally:
        self.signals.finished.emit()  # Done

和信号

class WorkerSignals(QtCore.QObject):
    '''
    Defines the signals available from a running worker thread.

    Supported signals are:

    finished
        No data

    error
        `tuple` (exctype,traceback.format_exc() )

    result
        `object` data returned from processing,anything

    progress
        `int` indicating % progress

    '''
    error = QtCore.Signal(tuple)
    started = QtCore.Signal()
    finished = QtCore.Signal()
    progress = QtCore.Signal(int)
    result = QtCore.Signal(object)
    data = QtCore.Signal(dict)

要执行的函数被下面的函数调用

def exe_worker_run(self,WorkerPool,function,arguments):
    Worker = thread.Worker(function,arguments)
    Worker.signals.started.connect(self.sig_thread_start)
    Worker.signals.error.connect(self.sig_thread_error)
    Worker.signals.result.connect(self.sig_thread_result)
    Worker.signals.finished.connect(self.sig_thread_finish)
    WorkerPool.start(Worker)

发出结果的信号连接到函数

def sig_thread_result(self,result):
    for key in result.keys():
        try:
            dfrm = getattr(self,key)
            print('{} {} loaded!!!'.format(time.time(),key))
        except:
            pass

主要问题是每个函数的结果都是在所有函数执行完后才发出的。所以我需要的是允许保持 QRunnable 的执行直到前一个 QRunnable 的结果可用的解决方案。

解决方法

您可以将任务组织到队列中并通过信号槽机制将它们一一传递给工作人员执行。通过这种方式,您可以使用一次计算的结果来安排下一次计算。

from PySide2 import QtCore,QtWidgets,QtGui

class Task:
    def __init__(self,taskId):
        self._taskId = taskId

    def taskId(self):
        return self._taskId

    def execute():
        pass

class TaskPlusOne(Task):

    def __init__(self,taskId,value):
        super().__init__(taskId)
        self._value = value

    def execute(self):
        QtCore.QThread.currentThread().sleep(3)
        return self._value + 1

class Worker(QtCore.QObject):

    complete = QtCore.Signal(int,object)

    def append(self,task):
        print("execute",task.taskId())
        res = task.execute()
        self.complete.emit(task.taskId(),res)

class Window(QtWidgets.QWidget):

    task = QtCore.Signal(object)

    def __init__(self,parent = None):
        super().__init__(parent)

        worker = Worker()
        self.task.connect(worker.append)
        worker.complete.connect(self.onComplete)
        thread = QtCore.QThread()
        worker.moveToThread(thread)
        thread.start()

        self._thread = thread
        self._worker = worker

        self._queue = [TaskPlusOne(0,0)]
        self.executeOne()

    def executeOne(self):
        queue = self._queue
        if len(queue) == 0:
            print("task queue is empty")
            return
        self.task.emit(queue.pop(0))

    def executeAll(self):
        while len(self._queue) > 0:
            self.executeOne()

    def onComplete(self,res):
        print("onComplete",taskId)
        if res < 2:
            print("append task to queue")
            self._queue.append(TaskPlusOne(taskId + 1,res))
        self.executeOne()

    def closeEvent(self,event):
        thread = self._thread
        thread.quit()
        thread.wait()
        super().closeEvent(event)

if __name__ == "__main__":
    app = QtWidgets.QApplication([])

    widget = Window()
    widget.show()

    app.exec_()

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。