将繁重的 QTimer 任务作为 QThread 运行 [英] Running a heavy QTimer task as a QThread

查看:77
本文介绍了将繁重的 QTimer 任务作为 QThread 运行的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一项繁重的任务,每 500 毫秒就会持续运行一次.它包括更新 GUI 元素,我需要随时访问其变量.

I have a heavy task that constantly runs every 500ms. It consists of updating GUI elements and I need access to its variables at all times.

执行的任务:一个动态更新的列表,每 500 毫秒,循环遍历该列表,并在其中包含的元素上执行任务.有时我没有元素,有时我有很多.

The task performed: A list that is dynamically updated and every 500ms, a loop goes through that list and performers tasks on the elements contained inside of it. Sometimes I have no elements in it, and sometimes I have plenty.

加载列表时,用户开始遇到鼠标移动、按键等延迟.毫无疑问,这是因为每 500 毫秒执行一次繁重的任务.

When the list is loaded, the user starts to encounter a delay in mouse movement, key presses, and such. And that's without a doubt due to the heavy task performed every 500ms.

有没有办法让我将这个 QTimer 任务放入 QThread 并不断访问它的元素以更新其中包含的列表?

Would there be a way for me to put this QTimer task into a QThread and constantly have access to it's elements in order update the list contained inside of it?

换句话说,我希望它始终在后台运行,但也能够在任何给定时刻更新其中使用的列表.

In other words, I would like it to run in the background at all times but also have the ability to update the list used inside of it at any given moment.

我正在使用 PySide2;我看过一些例子,但没有一个适合我想要完成的任务.

I'm using PySide2; I've seen examples but none that fit what I'm trying to accomplish.

示例:我想更新aList"如我所愿,来自主线程的元素.如果列表为空,则 for 循环不执行任何操作.否则,它会遍历元素并给它们加 1.

EXAMPLE: I would like to update the "aList" element from the main thread as I wish. If the list is empty, then the for loop does not do anything. Otherwise, it loops over the elements and adds 1 to them.

运行"函数应该设置一个 500ms 的 Qtimer.

The "run" function should have a Qtimer of 500ms set on it.

有时列表可能是空的,有时会充满元素.它的大小由 GUI 线程控制.

Sometimes the list may be empty and at times full of elements. It's size is controlled from the GUI thread.

 from PySide2 import QtCore
 from PySide2 import QtGui 
 from PySide2 import QtWidgets

 import sys
 import time

 class RxProcess(QtCore.QThread):

     output = QtCore.Signal()

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

    
     def run(self):
    
         # Loop through list
         for element in self.aList: 
        
             element += 1

             # Print to the gui the element that was just updated in the list
             self.output.emit(element)

推荐答案

使用 QThread 很难实现该逻辑(您将不得不使用 QThread.msleep、mutex 等).相反,一个简单的解决方案是每 T 秒创建一个新线程,并使用 threading.Thread + QTimer 实现(也可以使用 QThreadPool + QRunnable + QTimer 实现):

With QThread it is difficult to implement that logic (you would have to use QThread.msleep, mutex, etc). Instead a simple solution is to create a new thread every T seconds and that will be implemented using threading.Thread + QTimer (can also be implemented with QThreadPool + QRunnable + QTimer):

import random
import sys
import threading
import time


from PySide2 import QtCore, QtWidgets
import shiboken2


class Worker(QtCore.QObject):
    output = QtCore.Signal(object)


def long_running_function(values, worker):
    for element in values:
        time.sleep(0.1)
        if shiboken2.isValid(worker):
            worker.output.emit(element)


class Widget(QtWidgets.QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)

        self.label = QtWidgets.QLabel(alignment=QtCore.Qt.AlignCenter)
        self.button = QtWidgets.QPushButton("Start")

        lay = QtWidgets.QVBoxLayout(self)
        lay.addWidget(self.button)
        lay.addWidget(self.label)

        self.timer = QtCore.QTimer(interval=500)

        self.button.clicked.connect(self.handle_clicked)
        self.timer.timeout.connect(self.launch_task)

    def handle_clicked(self):
        if self.button.text() == "Start":
            self.timer.start()
            self.button.setText("Stop")
        elif self.button.text() == "Stop":
            self.timer.stop()
            self.button.setText("Start")

    def launch_task(self):
        values = random.sample(range(1, 50), 20)
        worker = Worker()
        worker.output.connect(self.label.setNum)
        threading.Thread(
            target=long_running_function,
            args=(values, worker),
            daemon=True,
        ).start()


if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    w = Widget()
    w.show()
    sys.exit(app.exec_())

这篇关于将繁重的 QTimer 任务作为 QThread 运行的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆