用了一下QT的线程池,为了能发出信号写了一个特别丑陋的代码

QT线程池中使用的是QRunnable,这个子线程没有继承QObject,导致无法使用QT的信号和槽,而我需要做一个进度条监控线程池总进度,于是我不得不在其中套了一个类种类,继承QObject,唯一的作用就是发送信号,告诉槽函数这里完成了一个进度 :sweat:
我又查了一下,QThreadPool同样没有相关的完成任务信号,这设计感觉不太科学
image

你這個用全局變量會不會方便些?

全局变量也得写线程锁,都那样

没事不要使用 Qt 的线程池,因为 Qt 的线程使用不当容易崩溃,尽量使用 Python 的。而在子线程里面,也不要使用 signal/slot 通知 UI 线程,建议使用 QMetaObject.invokeMethod() 调用。

因为 Python 有 GIL,所以实际上你使用线程也加速不了啥。如果你只是为了做一些网络工作的话,你可以考虑使用一下 eventlet-pyqt,能够在 PyQt 里面使用 eventlet 搞网络操作不需要搞多线程,所以没有和多线程通信的麻烦。或者我有个朋友做了一个 qtinter,换成 asyncio 协程

https://qtinter.readthedocs.io

发一段代码给你看看,做网络请求的时候不需要启动线程:

import logging; logging.basicConfig(level = logging.DEBUG)
from hgoldfish.utils import eventlet
from eventlet.green.urllib.request import urlopen

from PyQt5.QtCore import Qt
from PyQt5.QtGui import QApplication, QTextBrowser


class TestWidget(QTextBrowser):
    def __init__(self):
        QTextBrowser.__init__(self)
        self.operations = eventlet.GreenletGroup()
        self.setPlainText("click middle button to navigate www.163.com")

    def mousePressEvent(self, event):
        if event.button() == Qt.MidButton:
            self.operations.spawn(self.getpage)
            self.operations.spawnWithName("print_number", self.printNumbers)
        QTextBrowser.mousePressEvent(self, event)

    def printNumbers(self):
        i = 0
        while True:
            eventlet.sleep(0.1)
            i += 1
            self.append(str(i))

    def getpage(self):
        page = urlopen("http://www.163.com/").read().decode("gbk", "replace")
        self.setPlainText(page)
        self.operations.kill("print_number")

if __name__ == "__main__":
    app = QApplication([])
    w = TestWidget()
    w.show()
    eventlet.start_application(quitOnLastWindowClosed = True)

感谢!我调用的是ffmpeg+网络请求,线程池只是看有了就拿来用了了解的不多,我学习一下

那建议你把 ffmpeg 独立出来,写成所谓的纯函数,输出只依赖于输入,不访问函数外资源的那种函数,然后用 python 的线程池调用。网络的归网络,计算的归计算。

我之前用 Qt 的线程,很容易崩——只要你在线程还在运行的时候,意外销毁了这个线程就会崩:

class MainWindow:
    def on_ok_button_clicked(self):
        self.thread = TestThread()
        self.thread.start()

以上代码容易崩溃,你可以想想是为啥。同样的代码换成 python 的threading.Thread就没问题。不管怎么样,python 程序有可能不抛异常直接崩溃都是大问题。

太深奥了!我现在就调用一下ffmpeg-python,终止线程的时候是清空还没运行的然后等现有的运行完,不敢强杀线程。我对这东西的理解还是脚本小子的层次,我能让程序跑起来就已经殚精竭虑了
image