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

如何在Python中并行运行不同处理速率的函数(数据读取+动画更新)

解决方案:多进程+线程安全队列实现数据采集与动画解耦

核心思路

把数据读取和动画渲染拆成两个独立进程,彻底解耦两者的执行逻辑:

  • 子进程:专门运行readData,以10KHz速率读取数据,将最新数据存入线程安全的跨进程队列
  • 主进程:负责动画渲染,每60fps(约16.6ms)从队列中获取最新数据快照,更新帧内容

动画渲染的耗时不会再影响数据读取的实时性,队列会自动缓冲并传递数据,避免数据流混乱。

具体实现步骤

1. 选择合适的队列

用multiprocessing.Queue,它原生支持跨进程通信,内部已实现同步机制,无需额外加锁。如果只需要保留最新一帧数据,可将队列容量设为1,新数据会自动覆盖旧数据(或存新数据前清空队列)。

2. 数据采集子进程

写独立函数作为子进程入口,循环读取数据并写入队列:

import multiprocessing
import time

def data_collector(queue):
    while True:
        # 读取数据(如果readData是硬件阻塞读取,可省略sleep)
        data = readData()
        # 清空队列,只保留最新数据
        while not queue.empty():
            try:
                queue.get_nowait()
            except multiprocessing.queues.Empty:
                pass
        queue.put(data)
        # 控制100us间隔(非阻塞读取时需加)
        time.sleep(0.0001)

3. 动画渲染主进程

主进程启动动画循环,每帧从队列取最新数据更新画面(以matplotlib为例):

import matplotlib.pyplot as plt

def animate(frame, queue):
    # 获取最新数据,队列空时用上一次缓存
    try:
        latest_data = queue.get_nowait()
    except multiprocessing.queues.Empty:
        latest_data = animate.last_data
        if latest_data is None:
            return
    animate.last_data = latest_data
    
    # 替换为你的动画更新逻辑
    line.set_ydata(latest_data)
    return line,

if __name__ == "__main__":
    # 创建容量为1的队列
    data_queue = multiprocessing.Queue(maxsize=1)
    
    # 启动数据采集子进程
    collector_process = multiprocessing.Process(target=data_collector, args=(data_queue,))
    collector_process.daemon = True  # 主进程退出时自动终止子进程
    collector_process.start()
    
    # 初始化动画
    fig, ax = plt.subplots()
    line, = ax.plot([0]*100)
    animate.last_data = [0]*100
    
    # 启动60fps动画循环
    ani = plt.FuncAnimation(
        fig, animate, fargs=(data_queue,),
        interval=1000//60,
        blit=True
    )
    
    plt.show()
    
    # 主进程结束前终止子进程
    collector_process.terminate()

其他工具的局限性

  • asyncio:受GIL限制,CPU密集的动画渲染会阻塞事件循环,无法稳定维持10KHz的读取速率
  • Thread:同样受GIL约束,动画渲染的CPU占用会挤占数据读取线程的执行时间,导致数据丢包或延迟
  • Ray:功能过于重型,没必要为简单的跨进程通信引入分布式框架,徒增复杂度

注意事项

  • 如果readData是硬件阻塞读取(比如串口、ADC),可省略time.sleep,由硬件本身控制读取间隔
  • 若需要保留历史数据,可增大队列容量,动画按需读取对应数据段
  • 子进程设为守护进程,避免主进程退出后残留僵尸进程

内容的提问来源于stack exchange,提问作者Achen

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 14:05:18