Django结合threading使用全局变量控制树莓派硬件的问题咨询
问题原因与解决方案
为什么修改cfg.RUNNING不生效
Django默认的开发模式会启动两个独立进程:一个负责监听代码变更自动重载,另一个负责处理用户请求。你在apps.py的ready方法中启动的runner线程运行在自动重载的主进程内,而视图函数修改的cfg.RUNNING是请求处理进程内的变量,两个进程内存空间完全隔离,变更自然无法互相感知。就算切换到生产环境,只要启动了多个worker进程,同样会遇到这个问题。
临时验证方法
如果你只是想快速验证当前逻辑的正确性,可以关闭Django的自动重载,启动服务时执行:
python manage.py runserver --noreload
此时服务只会启动一个进程,你写的测试代码就能正常运行了。
符合需求的长期架构方案
针对你提到的4个实现目标,推荐的架构设计如下:
- 统一管理串口和长运行任务
单独启动一个独立的后台常驻进程,专门负责串口初始化、游戏线程管理、硬件交互逻辑,不要和Django的请求处理进程混在一起。串口实例只保存在这个进程的全局变量中,避免多进程访问串口冲突,也解决了串口对象无法序列化存数据库的问题。 - 进程间通信传递指令
Django视图和后台进程之间用轻量的IPC机制通信,树莓派场景推荐用Redis做消息队列/状态存储:- 视图收到启动/终止任务的请求时,往Redis的指定频道发指令,或者写入任务队列
- 后台进程订阅对应频道/轮询任务队列,收到启动指令后,从自身全局变量拿到串口实例,启动新的游戏线程执行逻辑
- 线程安全的终止机制
每个游戏线程用threading.Event做终止标识,不要用普通布尔变量:
终止线程时只要调用对应线程的import threading class GameThread(threading.Thread): def __init__(self, serial_port, name): super().__init__(daemon=True) self.serial_port = serial_port self.name = name self.stop_event = threading.Event() # 要暴露给前端的状态变量 self.status = {"progress": 0, "current_step": ""} def run(self): # 游戏逻辑循环 while not self.stop_event.is_set(): # 执行硬件操作、游戏逻辑 pass # 退出前做资源清理stop_event.set()即可,线程会在下次循环检测到后安全退出。所有运行中的线程存在后台进程的字典里,用任务ID做key,方便快速查找操作。 - 线程状态同步
后台进程定期把所有运行中线程的状态变量写入Redis,Django视图收到状态查询请求时,直接读Redis里的数据返回给前端展示即可,不需要直接访问游戏线程。 - 额外注意:串口是独占资源,多线程操作时要加
threading.Lock锁,每次读写串口前获取锁,操作完成后释放,避免数据错乱。
内容的提问来源于stack exchange,提问作者HamYam
相关产品推荐
相关产品推荐

