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
相关产品推荐
相关产品推荐

