如何在python中完成任务后停止线程?

Posted

技术标签:

【中文标题】如何在python中完成任务后停止线程?【英文标题】:How to stop a thread after the task is finished in python? 【发布时间】:2021-12-25 13:05:29 【问题描述】:

在下面的代码中,当我第一次单击按钮后,微调器 (MDSpinner) 将开始旋转,logging.info() 将被定向到 MDLabel。但是在我第二次点击按钮后,会有两份logging.info() 指向MDLabel。任务my_thread 完成后如何停止线程?提前致谢。

import kivy
from kivy.lang import Builder
import logging
import threading
from kivy.uix.floatlayout import FloatLayout
from kivymd.app import MDApp
from kivy.clock import Clock

import time

root_kv = '''
BoxLayout:
    id: main
    orientation: "vertical"
    spacing: "20dp"
    padding: "50dp", "10dp", "50dp", "10dp"

    MDRaisedButton:
        id: button4read_mtx
        size_hint: None, None
        size: 4 * dp(48), dp(48)
        text: "Start"
        opposite_colors: True
        pos_hint: "center_x": 0.5, "center_y": 0.5
        on_release: app.analyze_data()
    MDSpinner:
        id: spinder4button
        size_hint: None, None
        size: dp(46), dp(46)
        pos_hint: 'center_x': .5, 'center_y': .5
        active: False
    MDLabel:
        id: test_label_log
        text: "Log"
        halign: "left"
'''

exit_flag = 0
def my_thread(log, app):
    app.root.ids.spinder4button.active = True
    for i in range(5):
        time.sleep(1)
        log.info("Step %s", i)
    app.root.ids.spinder4button.active = False

class MDLabelHandler(logging.Handler):

    def __init__(self, label, level=logging.NOTSET):
        logging.Handler.__init__(self, level=level)
        self.label = label

    def emit(self, record):
        "using the Clock module for thread safety with kivy's main loop"
        def f(dt=None):
            self.label.text += "\n" + self.format(record)  #"use += to append..."
        Clock.schedule_once(f)


class MyApp(MDApp):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)

    def build(self):
        root = Builder.load_string(root_kv)
        return root
    def analyze_data(self):
        log = logging.getLogger("my.logger")
        log.level = logging.DEBUG
        log.addHandler(MDLabelHandler(self.root.ids.test_label_log, logging.DEBUG))
        #thread_info = _thread.start_new(my_thread, (log, self, ))
        #print(thread_info)
        x = threading.Thread(target=my_thread, args=(log, self, ))
        x.start()

if __name__ == '__main__':
    MyApp().run()

【问题讨论】:

您可以通过在其中安装跟踪来终止线程。这将导致线程退出。对于一种可能实现的示例,我们在这里:web.archive.org/web/20130503082442/http://mail.python.org/… 【参考方案1】:

当任务完成时,线程应该终止。那不是问题。问题是每次运行analyze_data() 时都会添加一个新的日志记录处理程序。解决方法是只添加一个处理程序:

class MyApp(MDApp):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.log = None

    def build(self):
        root = Builder.load_string(root_kv)
        return root

    def analyze_data(self):
        if self.log is None:
            self.log = logging.getLogger("my.logger")
            self.log.level = logging.DEBUG
            self.log.addHandler(MDLabelHandler(self.root.ids.test_label_log, logging.DEBUG))
        #thread_info = _thread.start_new(my_thread, (log, self, ))
        #print(thread_info)
        x = threading.Thread(target=my_thread, args=(self.log, self, ))
        x.start()

【讨论】:

谢谢。你的代码完美无缺。我只是不明白为什么我的代码不起作用。我的理解是每次调用analyze_data() 时都会在我的代码中创建一个新的log。你能否给我更多的解释。谢谢。 实际上,它不是一个新的记录器,而是一个新的Handler,每次都会在你的代码中创建。当调用log.info() 时,记录器会遍历所有Handlers

以上是关于如何在python中完成任务后停止线程?的主要内容,如果未能解决你的问题,请参考以下文章

如何在python中启动一个线程池并在一个线程完成时停止?

如何让一个线程停止执行另一个任务然后回来?

如何在android中停止异步任务线程?

线程池的停止

在某些情况发生后停止线程 ScheduledThreadPoolExecutor

如何正确停止线程