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

Pyserial使用in_waiting致CPU占用过高的低负载串口监听方案咨询

解决方案

你当前CPU占用过高的核心原因是循环无阻塞轮询in_waiting属性,无数据时会以最高频率反复调用该接口,导致空转占用CPU。

方案1:轮询加短休眠(最低改造成本)

如果对报文延迟要求不高,直接在循环末尾添加毫秒级休眠即可,可将CPU占用降到接近0:

import time

def listen(self):
    """
    Main listener
    """
    while self.doListen:
        if self.bus.ser.in_waiting:
            msg = self.bus.read(self.bus.ser.in_waiting)
            self.msgQueue.put_nowait(msg)
        # 1ms休眠可根据实时性要求调整,常规串口波特率下不会丢包
        time.sleep(0.001)

方案2:阻塞读首字节+批量读剩余(推荐,CPU占用最低)

如果设置timeout=None后read(1)仍然返回空,优先排查串口配置是否生效、是否有其他线程同时操作串口、串口驱动是否存在兼容性问题,这不属于pyserial的常规表现。确认read(1)可正常阻塞后,可以用阻塞等首字节的方式,无数据时线程完全休眠不占用CPU,同时适配可变长度无分隔符的报文场景:

import time

def listen(self):
    """
    Main listener
    """
    while self.doListen:
        # 无数据时阻塞在此,不占用CPU
        first_byte = self.bus.ser.read(1)
        if not first_byte:
            time.sleep(0.01)
            continue
        # 读取当前缓冲区所有剩余数据
        remaining = self.bus.ser.read(self.bus.ser.in_waiting)
        msg = first_byte + remaining
        self.msgQueue.put_nowait(msg)

方案3:IO多路复用(适用于Linux/macOS系统)

类Unix系统下可以用select监听串口文件描述符的可读事件,无数据时线程阻塞在select调用上,CPU占用极低:

import select

def listen(self):
    """
    Main listener
    """
    while self.doListen:
        # 超时设为1秒,可响应doListen的终止信号
        readable, _, _ = select.select([self.bus.ser.fileno()], [], [], 1)
        if readable:
            msg = self.bus.read(self.bus.ser.in_waiting)
            self.msgQueue.put_nowait(msg)

注:Windows系统下pyserial的串口句柄不支持select调用,该方案无法使用。

额外建议

如果你的串口波特率超过1Mbps、对实时性要求极高,建议使用C扩展或者更底层的串口库处理,Python层的调度延迟可能会影响数据接收稳定性。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 10:48:03