PyQt5 的一个线程占用 CPU 为何会导致另一个线程及UI线程响应变慢?

发布于 2022-09-12 02:38:17 字数 1614 浏览 19 评论 0

我之前是搞嵌入式的,现在要写一个上位机,选择使用 Python+PyQt5 来完成。我的程序有两个执行线程以及一个主线程,主线程初始化完两个执行线程之后,一个执行线程进行串口的数据交互,另一个线程执行一个比较耗时的操作( OpenCV 图像处理),完全占满 CPU 。 这两个线程都是使用 QThread 来完成的,现在遇到了一个问题:图像处理线程长时间的计算,会导致串口线程出现响应变慢的现象(串口丢包导致通信失败),与此同时主线程的 UI 操作也会卡顿。 下面是部分代码(版面原因,部分无用代码已删除)。
这个程序里只有一个已知的耗费时间的代码(在下面程序中用image_proc表示),删掉这个函数程序便会变回正常速度。

class MainWindowClass(QMainWindow, Ui_MainWindow):
    def __init__(self):
        super(MainWindowClass, self).__init__()  # 初始化父类
        self.setupUi(self)  # 初始化窗口

        self.imgProcTrd = ThreadImageProc(op_param, op_cam_idx)  # 创建图像处理线程
        self.imgProcTrd.signalImageSend.connect(self.callback_image_display)  # 连接回传到 GUI 的事件

        self.serialCommTrd = ThreadSerialComm()  # 创建串口通信线程
        self.serialCommTrd.signalSerialStatus.connect(self.callback_serial_event)


class ThreadImageProc(QThread):
    #  通过类成员对象定义信号对象
    signalImageSend = pyqtSignal(numpy.ndarray)

    def __init__(self, op_param, cam_idx):
        super(ThreadImageProc, self).__init__()

    def run(self):
        while True:
            ret, cap_img = cap.read()
            img = self.image_proc(cap_img)
            self.signalImageSend.emit(img)


class ThreadSerialComm(QThread):
    signalSerialStatus = pyqtSignal(list)  # 串口上报 

    def __init__(self):
        super(ThreadSerialComm, self).__init__()

    def run(self): 
        while True:
        # 省略串口通信函数

想请问一下各位大佬这是什么情况?有没有解决方案? RTOS 是抢占式系统,即使是单核心的嵌入式处理器也会保证每过一个 Tick 执行一次任务调度来确保高优先级的任务得以抢占 CPU 。按照我的理解,电脑这种多核心处理器应该是把多个线程分配给多个核心执行的(仅仅是我很初级的理解,望赐教),为什么会出现这种子线程卡死其他线程甚至 UI 线程的呢?有没有什么解决方法?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

榕城若虚 2022-09-19 02:38:17

会不会是python语言本身的问题? Python对于非IO相关的多线程存在GIL锁锁住的设定,即多线程纯计算是不存在的。
根据我查找的资料,python对于不涉及io的长时间运算,是只能同一时间采用一个核进行运算的,我推测你的图像处理应该是cpu密集型的操作吧,应该不涉及大量IO吧?那运算的时候另外的线程就是阻断的,可能这个是卡顿的原因。
一般在这种情况是推荐多进程处理,不知道pyQt是否支持多线程?
更激进的方法是选择没有GIL的python解释器比如PyPy等,但对其他依赖python的应用是否会造成影响就不得而知了。
另一个思路是可以利用GIL的特性,在你处理图像的期间附带增加轻量的IO操作,诱使GIL释放,让UI线程继续运行。
这个是python官方关于GIl的wikiGlobalInterpreterLock
也可以看一下这两个StackOVerflow的帖子:

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文