QT线程池中使用的是QRunnable,这个子线程没有继承QObject,导致无法使用QT的信号和槽,而我需要做一个进度条监控线程池总进度,于是我不得不在其中套了一个类种类,继承QObject,唯一的作用就是发送信号,告诉槽函数这里完成了一个进度
我又查了一下,QThreadPool同样没有相关的完成任务信号,这设计感觉不太科学
你這個用全局變量會不會方便些?
全局变量也得写线程锁,都那样
没事不要使用 Qt 的线程池,因为 Qt 的线程使用不当容易崩溃,尽量使用 Python 的。而在子线程里面,也不要使用 signal/slot 通知 UI 线程,建议使用 QMetaObject.invokeMethod() 调用。
因为 Python 有 GIL,所以实际上你使用线程也加速不了啥。如果你只是为了做一些网络工作的话,你可以考虑使用一下 eventlet-pyqt,能够在 PyQt 里面使用 eventlet 搞网络操作不需要搞多线程,所以没有和多线程通信的麻烦。或者我有个朋友做了一个 qtinter,换成 asyncio 协程
发一段代码给你看看,做网络请求的时候不需要启动线程:
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,终止线程的时候是清空还没运行的然后等现有的运行完,不敢强杀线程。我对这东西的理解还是脚本小子的层次,我能让程序跑起来就已经殚精竭虑了