如何解决Streamlit中启动线程后无法点击停止按钮的问题?
问题解决方法
核心错误分析
你的代码存在两个关键问题,导致无法正常点击Stop按钮:
- 线程创建逻辑错误:
store()方法里,threading.Thread(target=self.run())是直接调用了run()函数,而非传递函数对象给target参数。这会让主线程直接进入run()的无限循环,完全阻塞,根本没启动新线程。 - Streamlit状态丢失:Streamlit每次交互(点击按钮)都会重新运行整个脚本,原有的
Test实例会被重新创建,导致无法获取到之前启动的线程对象。
修改后的代码
1. 修正Test类的线程逻辑
import threading import time class Test(): def __init__(self) -> None: self.stop_threads = False self.t1 = None # 提前初始化线程对象变量 def run(self): # 优化循环条件,提前判断停止标志 while not self.stop_threads: print('thread running') time.sleep(5) def store(self): # 修复target参数:传递函数对象而非直接调用函数 self.t1 = threading.Thread(target=self.run) self.t1.start() def stop(self): # 先判断线程是否存在且存活 if self.t1 and self.t1.is_alive(): self.stop_threads = True self.t1.join() self.stop_threads = False # 重置状态,方便下次启动 print('thread killed')
2. 修正Streamlit界面的状态保存逻辑
from test2 import Test import streamlit as st # 使用session_state保存Test实例,避免每次交互重新创建对象 if 'test_obj' not in st.session_state: st.session_state.test_obj = Test() obj = st.session_state.test_obj if st.button("Run"): # 防止重复启动线程 if not obj.t1 or not obj.t1.is_alive(): obj.store() st.success("线程已启动") if st.button("Stop"): obj.stop() st.success("线程已停止")
关键修改说明
- 线程创建修正:
target=self.run传递的是函数引用,让子线程去执行run逻辑,主线程不会被阻塞。 - 循环条件优化:将
while True改为while not self.stop_threads,设置停止标志后无需等待sleep结束就能退出循环。 - Streamlit状态管理:通过
st.session_state保存Test实例,确保每次交互操作的是同一个对象,能正确获取到已启动的线程。 - 重复启动防护:判断线程是否存活,避免多次点击Run按钮创建多个重复线程。
内容的提问来源于stack exchange,提问作者Myron Dsilva
相关产品推荐
相关产品推荐

