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

Celery中使用pyserial执行定时串口写入任务CPU占用过高问题排查

问题根源

你的代码核心问题是忙等待循环:while True持续轮询时间差,没有给CPU留出空闲时间,导致单个核心被完全占用(双核环境下显示50%使用率)。

优化方案

将忙等待改为精准休眠,同时补充Celery任务的优雅退出逻辑,避免资源泄漏:

修改后的代码

import time
import serial
from celery import shared_task

@shared_task(bind=True)
def start_serial_acquisition(self, idObj, porta_COM):
    # 用with语句自动管理串口资源,任务结束时自动关闭
    with serial.Serial(porta_COM, 38400, timeout=0.1) as ser:
        packet = b'\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80'
        interval = 0.150  # 明确设置150ms发送间隔
        
        while True:
            # 检测Celery任务是否被取消,支持优雅退出
            if self.request.is_aborted():
                break
                
            # 发送数据包
            ser.write(packet)
            
            # 计算并休眠到下一次发送的剩余时间,抵消发送操作的耗时
            time.sleep(max(0, interval - (time.monotonic() % interval)))
    
    return "Serial acquisition stopped gracefully"

关键优化点

  • 替换忙等待为休眠:原循环每秒执行数千次时间检查,现在每次发送后计算剩余等待时间并休眠,CPU在休眠期间完全空闲。
  • 自动管理串口资源:with语句确保任务结束时自动关闭串口,避免资源泄漏。
  • 支持任务优雅退出:self.request.is_aborted()捕获Celery的任务取消信号,避免任务无限占用资源。
  • 精准控制发送间隔:通过time.monotonic() % interval计算当前周期已流逝的时间,避免间隔累积误差。

额外优化建议

如果串口发送操作本身耗时较长(比如硬件阻塞),可以改用以下方式保证间隔稳定:

start_time = time.monotonic()
ser.write(packet)
elapsed = time.monotonic() - start_time
time.sleep(max(0, interval - elapsed))

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 02:10:20