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

多进程自更新对象阻塞问题:高刷新率显示如何实时获取硬件最新值

多进程自更新对象阻塞问题:高刷新率显示如何实时获取硬件最新值

看起来你碰到了多进程同步里的经典坑——慢节奏的硬件读取进程把高刷新率的显示进程给拖慢了。核心问题应该是你当前的共享状态(管道)用了阻塞式的交互逻辑,导致显示进程每次都得等硬件进程更新完才能拿到数据,而不是直接抓取最新的已更新值。我给你几个实际可落地的解决思路:

一、用非阻塞队列丢弃旧值,只取最新数据

最直接的方案是用multiprocessing.Queue,让硬件进程不断把最新的传感器数据塞进队列,显示进程每次刷新时,先把队列里所有旧数据清空,只取最后一条(也就是当前最新的硬件值)。这样显示进程完全不受硬件更新速度的限制,想刷多快就刷多快。

代码示例:

import multiprocessing
import board
import busio
import adafruit_lis2mdl
import adafruit_lsm303_accel
import time

class AccMag():
    def init(self):
        self.i2c = busio.I2C(board.SCL, board.SDA)
        self.mag = adafruit_lis2mdl.LIS2MDL(self.i2c)
        self.accel = adafruit_lsm303_accel.LSM303_Accel(self.i2c)

    def read_sensors(self):
        # 读取最新的传感器数据
        mag_val = self.mag.magnetic
        accel_val = self.accel.acceleration
        return mag_val, accel_val

# 硬件读取进程的工作函数
def hardware_worker(queue):
    acc_mag = AccMag()
    acc_mag.init()
    while True:
        # 读取传感器数据,塞进队列
        data = acc_mag.read_sensors()
        queue.put(data)
        # 硬件本身需要的更新间隔,可根据实际调整
        time.sleep(0.1)

# 显示进程的工作函数
def display_worker(queue):
    while True:
        # 清空队列里的旧数据,只保留最后一条最新的
        latest_data = None
        while not queue.empty():
            latest_data = queue.get(block=False)
        
        if latest_data is not None:
            mag_val, accel_val = latest_data
            # 这里执行你的显示更新逻辑
            print(f"显示更新:磁强计={mag_val}, 加速度计={accel_val}")
        
        # 模拟高刷新率的显示循环(比如60帧/秒)
        time.sleep(1/60)

if __name__ == "__main__":
    # 创建队列,设置最大长度避免内存溢出(可选)
    sensor_queue = multiprocessing.Queue(maxsize=10)
    
    # 启动两个进程
    hardware_proc = multiprocessing.Process(target=hardware_worker, args=(sensor_queue,))
    display_proc = multiprocessing.Process(target=display_worker, args=(sensor_queue,))
    
    hardware_proc.start()
    display_proc.start()
    
    hardware_proc.join()
    display_proc.join()

二、用共享内存+轻量锁实现快速读写

如果你不想用队列,也可以直接用共享内存变量(比如multiprocessing.Value/Array)配合锁,确保硬件进程更新数据和显示进程读取数据时的原子性,但要注意锁的粒度必须极小——只在读写共享变量的瞬间持有锁,绝对不要在锁里做硬件读取或显示渲染的操作。

代码示例:

import multiprocessing
import ctypes
import time
import board
import busio
import adafruit_lis2mdl
import adafruit_lsm303_accel

class AccMag():
    def init(self):
        self.i2c = busio.I2C(board.SCL, board.SDA)
        self.mag = adafruit_lis2mdl.LIS2MDL(self.i2c)
        self.accel = adafruit_lsm303_accel.LSM303_Accel(self.i2c)

    def read_sensors(self):
        mag_val = self.mag.magnetic
        accel_val = self.accel.acceleration
        return mag_val, accel_val

def hardware_worker(shared_mag, shared_accel, lock):
    acc_mag = AccMag()
    acc_mag.init()
    while True:
        mag_val, accel_val = acc_mag.read_sensors()
        # 加锁更新共享变量,更新完立刻释放
        with lock:
            shared_mag[0] = mag_val[0]
            shared_mag[1] = mag_val[1]
            shared_mag[2] = mag_val[2]
            shared_accel[0] = accel_val[0]
            shared_accel[1] = accel_val[1]
            shared_accel[2] = accel_val[2]
        # 硬件更新间隔
        time.sleep(0.1)

def display_worker(shared_mag, shared_accel, lock):
    while True:
        current_mag = [0,0,0]
        current_accel = [0,0,0]
        # 加锁读取共享变量,读完立刻释放
        with lock:
            current_mag[0] = shared_mag[0]
            current_mag[1] = shared_mag[1]
            current_mag[2] = shared_mag[2]
            current_accel[0] = shared_accel[0]
            current_accel[1] = shared_accel[1]
            current_accel[2] = shared_accel[2]
        
        # 执行显示更新
        print(f"显示更新:磁强计={current_mag}, 加速度计={current_accel}")
        # 高刷新率间隔
        time.sleep(1/60)

if __name__ == "__main__":
    # 创建共享数组(存储三维数据)
    shared_mag = multiprocessing.Array(ctypes.c_float, 3)
    shared_accel = multiprocessing.Array(ctypes.c_float, 3)
    # 创建锁
    data_lock = multiprocessing.Lock()
    
    hardware_proc = multiprocessing.Process(target=hardware_worker, args=(shared_mag, shared_accel, data_lock))
    display_proc = multiprocessing.Process(target=display_worker, args=(shared_mag, shared_accel, data_lock))
    
    hardware_proc.start()
    display_proc.start()
    
    hardware_proc.join()
    display_proc.join()

三、排查你当前阻塞的核心原因

你提到用了管道实现共享状态,大概率是显示进程用了pipe.recv()这种阻塞式调用——它会一直等硬件进程发数据,自然就被硬件的更新速度卡住了。如果非要用管道,得改成非阻塞的pipe.poll()先检查有没有数据,有就全部读完取最后一条,和队列的思路类似,但队列已经帮你封装好了这个逻辑,没必要自己造轮子。

另外要注意:硬件读取的循环里不要有过长的阻塞操作,显示进程的循环里也绝对不能有任何会拖慢帧率的阻塞代码(比如同步等待硬件数据)。

备注:内容来源于stack exchange,提问作者Sarazil

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.16 10:08:00