python任务完成后如何停止线程?
How to stop a thread after the task is finished in python?
在下面的代码中,我第一次点击按钮后,微调器 (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()
当任务完成时,线程应该终止。那不是问题。问题是您每次 运行 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()
在下面的代码中,我第一次点击按钮后,微调器 (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()
当任务完成时,线程应该终止。那不是问题。问题是您每次 运行 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()