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

如何用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 23:19:53