gpt4 book ai didi

python - 停止 qthread 中长时间运行的进程

转载 作者:行者123 更新时间:2023-12-01 02:21:26 25 4
gpt4 key购买 nike

我正在尝试使用youtube-dl从 youtube 下载视频的模块。我创建了一个简单的 GUI 来完成一些工作,我需要当用户单击开始按钮时,将调用线程并开始下载并使用 emit 发送数据。方法,当此数据到达read时函数位于 Main类,线程必须在调用 stop 后停止来自 GUI 的函数,我尝试使用 exec_() 在 qthread 中创建事件循环并使用 exit 停止线程,我也尝试使用 terminate但 GUI 卡住了。

我使用的代码是:

from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from youtube_dl import *

class Worker(QThread):
data = pyqtSignal(object)
def __init__(self):
super(Worker, self).__init__()
self.flag = True

def sendHook(self, data, status = {'status':'downloading'}):
self.data.emit(data)

def stop(self):
self.quit()
self.exit()

def run(self):
self.y = YoutubeDL({'progress_hooks':[self.sendHook]})
self.y.download(['https://www.youtube.com/watch?v=LKIXbNW-B5g'])
self.exec_()

class MainWindow(QMainWindow):
def __init__(self, *args, **kwargs):
super(MainWindow, self).__init__(*args, **kwargs)
layout = QVBoxLayout()
self.l = QLabel("Hello")
b = QPushButton("Start!")
b.pressed.connect(self.connectthread)
layout.addWidget(self.l)
layout.addWidget(b)
w = QWidget()
w.setLayout(layout)
self.setCentralWidget(w)
self.show()

def read(self, data):
self.thread.stop()

def connectthread(self):
self.thread = Worker()
self.thread.data.connect(self.read)
self.thread.start()

app = QApplication([])
window = MainWindow()
app.exec_()

最佳答案

通过在工作线程的 run() 方法中调用 self.exec_(),您可以在此线程上启动一个新的事件循环之后下载完成,然后该事件循环继续运行。这里不需要事件循环,如果您想使用 QObjects 的 moveToThread() 方法将它们从主事件循环中分离出来,则只需要一个单独的事件循环,但那就是这里不需要,您没有做任何需要 Qt 事件循环的事情。这也是为什么调用 stop()exit() 不会执行任何操作,它只会影响事件循环。停止该线程的唯一方法是其 terminate() 方法,这也是可行的:

from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from youtube_dl import *

class Worker(QThread):
data = pyqtSignal(object)
def __init__(self):
super(Worker, self).__init__()
self.flag = True

def sendHook(self, data, status = {'status':'downloading'}):
self.data.emit(data)

def stop(self):
self.terminate()
print("QThread terminated")

def run(self):
self.y = YoutubeDL({'progress_hooks':[self.sendHook]})
self.y.download(['https://www.youtube.com/watch?v=LKIXbNW-B5g'])
print("finished")

class MainWindow(QMainWindow):
def __init__(self, *args, **kwargs):
super(MainWindow, self).__init__(*args, **kwargs)
layout = QVBoxLayout()
self.l = QLabel("Hello")
b = QPushButton("Start!")
b.pressed.connect(self.connectthread)
layout.addWidget(self.l)
layout.addWidget(b)
w = QWidget()
w.setLayout(layout)
self.setCentralWidget(w)
self.thread = None
self.show()

def read(self, data):
print("read:", data)

def connectthread(self):
if self.thread is not None:
# already running
self.thread.stop()
self.thread = None
return
self.thread = Worker()
self.thread.data.connect(self.read)
self.thread.start()

app = QApplication([])
window = MainWindow()
app.exec_()

在这里,我更改了您的程序,以便第一次单击按钮时启动工作线程,第二次单击该线程时终止等等。

然而,以这种方式终止线程是危险的且不鼓励的。 Python 线程通常需要协作才能停止,因为按照设计,它们没有办法被中断。在这种情况下,它只能工作,因为 PyQt 控制着线程。

不幸的是,没有办法优雅地停止 youtube-dl 下载,请参阅 this related issue了解更多信息。一般来说,不能保证杀死调用 download() 的线程实际上会停止下载。 YoutubeDL 支持具有不同下载器的插件系统。例如,要下载 hls 流,则会启动外部 ffmpeg(或 avconv)进程,该进程不会通过终止工作线程而停止。对于内部使用其他线程或进程的下载程序,或者也使用 ffmpeg 执行的后处理步骤,情况也是如此。

如果您希望能够安全地停止下载,则必须使用单独的进程,以便可以使用 SIGINT 信号(与按 Ctrl-C 相同)来告诉它停止.

关于python - 停止 qthread 中长时间运行的进程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47921540/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com