如何用Python线程与多进程实现多函数不受耗时差异影响持续运行?
解决方案
核心思路
- 把耗时的
adjust_stepper放到独立线程后台运行,彻底避免阻塞主线程的read和display循环 - 用线程安全队列传递步进电机需要的控制参数(delta),主线程只负责生成数据,步进线程专注处理硬件操作
- 让步进线程自行维护电机位置
pos,消除多线程间的变量竞争风险 - 主线程持续执行
read和display,完全不等待步进线程的操作完成
修改后的代码
import threading as th from queue import Queue from gpiozero import OutputDevice as Opin from time import sleep # 初始化GPIO设备 stepdir = Opin(20) steppul = Opin(21) # 线程安全队列,最多保留1条最新指令(避免积压导致动作滞后) stepper_queue = Queue(maxsize=1) def read(): """读取传感器数据""" val1 = measured_value1 # 替换为实际传感器读取逻辑 val2 = measured_value2 # ... 其他传感器读取逻辑 return (val1, val2, ...) def display(parseme): """更新仪表显示""" val1 = parseme[0] val2 = parseme[1] # ... 数据解析逻辑 gauge_pos1(val1) sleep(0.0001) gauge_pos2(val2) sleep(0.0001) # ... 其他仪表更新逻辑 def stepper_worker(): """步进电机后台工作线程,自行维护位置状态""" current_pos = 0 # 初始化电机位置 while True: # 阻塞等待队列指令,超时0.001秒避免线程完全卡死 try: delta = stepper_queue.get(timeout=0.001) except: continue # 执行步进调整逻辑 if delta > 0.25: stepdir.on() steppul.on() sleep(0.005) steppul.off() sleep(0.005) current_pos += 1 elif delta < -0.25: # 修正原逻辑的阈值判断,确保反向调整的合理性 stepdir.off() steppul.on() sleep(0.005) steppul.off() sleep(0.005) current_pos -= 1 stepper_queue.task_done() # 启动步进电机线程,设置为守护线程,主程序退出时自动终止 stepper_thread = th.Thread(target=stepper_worker, daemon=True) stepper_thread.start() if __name__ == "__main__": while True: # 持续读取传感器数据 measures = read() # 立即更新显示,完全不等待步进电机操作 display(measures) # 计算delta(替换为实际的delta计算逻辑) delta = calculate_delta(measures) # 尝试放入新指令,队列满时丢弃旧指令,只保留最新的 try: stepper_queue.put_nowait(delta) except: stepper_queue.get_nowait() stepper_queue.put_nowait(delta)
关键细节说明
- 队列解耦:主线程只负责推送最新的
delta,步进线程异步处理,两者完全独立,不会互相阻塞 - 守护线程:
daemon=True确保主程序退出时,步进线程自动终止,无需手动清理 - 队列满处理:用
put_nowait和get_nowait保证队列只保留最新指令,避免步进电机处理过时数据导致动作滞后 - 位置独立维护:步进线程自行管理
current_pos,彻底避免多线程变量竞争问题
额外注意事项
- 如果
display中的gauge_pos函数操作的硬件不支持并发访问,需要给这些操作加线程锁(threading.Lock()),确保同一时间只有一个线程操作硬件 - 可根据实际需求调整队列
maxsize,若允许步进电机处理多条指令,可适当增大数值,但建议保持较小值避免滞后
内容的提问来源于stack exchange,提问作者Bryon Meredith
相关产品推荐
相关产品推荐

