为了账号安全,请及时绑定邮箱和手机立即绑定

如何停止线程的执行

如何停止线程的执行

眼眸繁星 2022-05-11 17:09:14
在下面的代码中,我有类 The Thread,它继承自线程以在不同的线程中执行任务,在这种情况下,任务是在 QLabel 中显示 .gif 图像,同时执行另一个任务。在这种情况下,当发出执行 Finish() 函数的信号时,tabWidget() 小部件从 index 变为 1但是当我们返回索引 0 时,我们可以看到 .gif 仍在 QLabel 中运行。所以我想知道如何停止该线程的执行,我试过了TheThread.kill()TheThread.stop()但它不起作用,这是带有 .ui 文件和 image.gif 的完整代码from PyQt5.QtWidgets import QMainWindow,QApplication,QTabWidget,QPushButton,QLabelfrom PyQt5 import QtCore,QtGuifrom PyQt5 import uicimport threadingimport timeclass TheThread(threading.Thread):    def __init__(self,obj,fun):        threading.Thread.__init__(self)        self.obj = obj        self.fun = fun    def run(self):        self.fun()class Main(QMainWindow):    signal = QtCore.pyqtSignal(object)    def __init__(self):        QMainWindow.__init__(self)        uic.loadUi("Test.ui",self)        self.Iniciar.clicked.connect(lambda:self.ShowImage())        self.signal.connect(self.Finish)        self._thread = TheThread(self,self.Fun1)    def ShowImage(self):        _movie = QtGui.QMovie("Loader.gif")        self.Animacion.setMovie(_movie)        self.Animacion.setScaledContents(True)        _movie.start()        self._thread.start()    def Fun1(self):        time.sleep(3)        self.signal.emit(0)    def Finish(self,signal):        if signal == 0:            time.sleep(1)            self.tabWidget.setCurrentIndex(1)            # TheThread.kill()            TheThread.stop()app = QApplication([])m = Main()m.show()app.exec_()
查看完整描述

2 回答

?
小怪兽爱吃肉

TA贡献1852条经验 获得超1个赞

您的描述与您的代码不符,也不符合正确的逻辑。

  • 作为 GUI 一部分的 gif 必须在主线程(GUI 线程)中执行,而繁重的任务则在辅助线程中执行。

  • 不要在主线程中使用 time.sleep()。

  • 它完成执行繁重的任务并不意味着它完成了 gif 的执行,您必须停止它。

考虑到上述情况,一种更简单的方法是创建一个存在于另一个线程中的 QObject 并在那里执行任务,这允许您添加启动和完成信号。

import os

import time

from functools import partial

from PyQt5 import QtCore, QtGui, QtWidgets, uic



current_dir = os.path.dirname(os.path.realpath(__file__))



def callback():

    # emulate task

    time.sleep(3.0)



class Worker(QtCore.QObject):

    started = QtCore.pyqtSignal()

    finished = QtCore.pyqtSignal()


    @QtCore.pyqtSlot(object)

    def task(self, fun):

        self.started.emit()

        fun()

        self.finished.emit()



class Main(QtWidgets.QMainWindow):

    def __init__(self, parent=None):

        super(Main, self).__init__(parent)


        filename = os.path.join(current_dir, "Test.ui")

        uic.loadUi(filename, self)


        self.Animacion.setScaledContents(True)


        thread = QtCore.QThread(self)

        thread.start()


        self._worker = Worker()

        self._worker.moveToThread(thread)

        self._worker.started.connect(self.show_image)

        self._worker.finished.connect(self.on_finished)


        wrapper = partial(self._worker.task, callback)

        self.Iniciar.clicked.connect(wrapper)


    @QtCore.pyqtSlot()

    def show_image(self):

        _movie = QtGui.QMovie("Loader.gif")

        self.Animacion.setMovie(_movie)


        self.Animacion.movie().start()


    @QtCore.pyqtSlot()

    def on_finished(self):

        self.tabWidget.setCurrentIndex(1)

        self.Animacion.movie().stop()



def main():

    import sys


    app = QtWidgets.QApplication(sys.argv)

    w = Main()

    w.show()

    sys.exit(app.exec_())



if __name__ == "__main__":

    main()


查看完整回答
反对 回复 2022-05-11
?
慕标5832272

TA贡献1966条经验 获得超4个赞

您使用了错误的线程,更好的方法是使用 Qt GUI 线程。stop()但是,除了使用orkill()方法(顺便说一句,它们不应该被设置为self._thread您定义的变量而不是TheThread类吗?)之外,我发现演示在 Python 中杀死线程的多种方法很好。这些技术本质上是骇人听闻的,但它们确实有效。


首先,您可以抛出异常,因为异常总是会阻止代码执行。此示例使用该ctypes库:


import ctypes


def get_id(self): 


    # returns id of the respective thread 

    if hasattr(self, '_thread_id'): 

        return self._thread_id 

    for id, thread in threading._active.items(): 

        if thread is self: 

            return id


def raise_exception(self): 

    thread_id = self.get_id() 

    res = ctypes.pythonapi.PyThreadState_SetAsyncExc(thread_id, 

          ctypes.py_object(SystemExit)) 

    if res > 1: 

        ctypes.pythonapi.PyThreadState_SetAsyncExc(thread_id, 0) 

        print('Exception raise failure') 


self._thread.raise_exception();

您还可以使用布尔标志变量,当设置为 true 时,执行一个break语句,结束程序。您可以在run()函数中定义线程,然后该join()方法基本上停止线程:


def run(): 

   while True:

       global stop_threads 

       if stop_threads: 

          break


self._thread = threading.Thread(target = run)  

self_thread.start() 

stop_threads = True

self_thread.join()

您还可以使用多处理模块,而不是使用线程,您可以使用进程,这非常相似,唯一的区别是线程在相同的内存空间中运行,而进程具有单独的内存。该terminate()方法杀死进程:


import multiprocessing 

import time 


def func(number): 

   for i in range(1, 10): 

       time.sleep(0.01) 

       print('Processing ' + str(number) + ': prints ' + str(number*i)) 


all_processes = [] 


for i in range(0, 3): 

   process = multiprocessing.Process(target=func, args=(i,)) 

   process.start() 

   all_processes.append(process) 


# Kill all processes after 0.03s  

time.sleep(0.03) 

for process in all_processes: 

   process.terminate()

最后,您可以通过将线程设置为守护进程来终止该线程。默认情况下,线程不会在程序结束时结束,所以守护线程是那些在主程序退出时被杀死的线程:


def func(): 

   while True: 

      time.sleep(0.5) 

      print('Thread alive, but it will die on program termination') 


self._thread = threading.Thread(target=func) 

self._thread.daemon = True

self._thread.start() 

time.sleep(2)

sys.exit()


查看完整回答
反对 回复 2022-05-11
  • 2 回答
  • 0 关注
  • 224 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号