You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python3 Threading问题:仅启动1个线程为何有2个活跃?如何修复?

问题原因分析
  • 线程重复创建:你在start_stop方法中没有区分启动和停止场景,无论点击Start还是Stop按钮,最后都会执行新建线程并启动的逻辑,多次点击后就会生成多个未销毁的旧线程,所以会出现Thread-1、Thread-2同时活跃的情况。
  • 停止状态被回滚:当你点击Stop按钮时,分支逻辑已经把运行状态调整为停止,随后又执行了self.running = not self.running,相当于把已经设为False的运行状态又改回了True,旧线程的while循环判断条件一直成立,自然永远不会退出。
修复代码

只需要调整start_stop方法的逻辑,停止操作仅修改运行状态通知旧线程退出,只有启动操作时才创建新线程,同时给线程设置daemon属性避免程序退出后残留线程,另外Kivy不允许子线程直接修改UI,新增Clock调度保证UI修改安全:

from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
from kivy.uix.label import Label
from time import sleep
import threading
from kivy.clock import Clock # 用于跨线程安全修改UI

class MyApp(BoxLayout):
    def __init__(self, **kwargs):
        super(MyApp, self).__init__(**kwargs)
        self.orientation = 'horizontal'
        self.running=False
        self.my_thread = None # 提前声明线程变量
        
        self.btn = Button(text='Start', size_hint_x=.1)        
        self.lbl = Label(size_hint_x=.9)
        
        self.add_widget(self.btn)
        self.btn.bind(on_press = self.start_stop)
        self.add_widget(self.lbl)

    def do_something(self,n):
        while self.running:
            # 子线程不能直接修改UI,用Clock调度到主线程执行
            Clock.schedule_once(lambda dt, val=n: setattr(self.lbl, 'text', str(val)), 0)
            sleep(.5)
            n += 1
        else:
            self.show_running_threads()
                
    def start_stop(self,event):
        if self.running:
            # 停止逻辑:只改状态,让旧线程自然退出
            self.btn.text = 'Start'
            self.running = False
        else:
            # 启动逻辑:改状态+新建线程启动
            self.btn.text = 'Stop'
            self.running = True
            # 设置daemon=True,主程序退出时线程自动销毁
            self.my_thread = threading.Thread(target = self.do_something,args = (0,), daemon=True)
            self.my_thread.start()

    def show_running_threads(self):
        runningThreads = []
        for thread in threading.enumerate():
            runningThreads.append(thread.name)
        # 这里也用Clock调度修改UI
        Clock.schedule_once(lambda dt: setattr(self.lbl, 'text', 'Running threads: ' + str(runningThreads) +\
                        '\n my_thread running = ' + str(self.my_thread.is_alive())), 0)
        
        print(runningThreads)
        
        if self.my_thread.is_alive():
            print('my_thread still running')
        else:
            print('my_thread cancelled\n','-'*80,sep='')
        
class MyLayout(App):
    def build(self):
        return MyApp()
      
        
if __name__ == '__main__':
    MyLayout().run()
额外说明

修改后点击Stop按钮时,self.running会被设为False,旧线程的while循环会马上终止,线程自然销毁,不会残留。只有点击Start按钮时才会创建新的线程,不会出现多个线程同时活跃的情况。

内容的提问来源于stack exchange,提问作者DaiBach

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.06 23:06:02