Py2转Py3适配queue模块后串口日志脚本输出空行问题咨询
问题根因
这个问题是Python2迁移Python3时的典型类型兼容问题,核心触发点有两个:
- pyserial接口返回值类型变了:Python2环境下pyserial的
readline()方法返回str类型,串口读超时无数据时返回空字符串"",原代码里if line != "":的判断可以正常过滤空读结果;但Python3环境下pyserial的readline()返回bytes字节类型,超时无数据时返回空字节b"",原判断是拿bytes和str类型的空串做比较,类型不匹配导致判断永远成立,所有空读结果都会被塞进输出队列。 - 脚本设置的串口读超时是0.05秒,意味着读线程每50ms就会触发一次超时返回空字节,这些本该被过滤的空值全部被送入输出流程,就出现了高频无限刷
b''的现象。同时Python3中bytes类型直接和字符串拼接输出时,会自动带上b'xxx'的类型标记,连正常的串口日志也会被包裹在字节串标记里,不符合日志阅读习惯。
最佳修复方案
修复时不需要改动整体队列、多线程的架构,只需要针对类型兼容问题做调整即可:
- 替换空值判断逻辑:不再用和空字符串比较的方式过滤空结果,改用长度判断,兼容bytes类型返回值,同时过滤掉仅含换行、空白符的无效行。
- 增加字节解码步骤:将串口读到的bytes内容按指定编码(串口日志通用UTF-8,遇到特殊设备也可换GBK)解码为普通字符串,解码时增加错误忽略规则,避免特殊字节触发解码崩溃。
- 顺带修复原代码的小逻辑bug:KeyboardInterrupt分支里的
sys.exit()位置错误,放在for循环内部会导致第一个串口线程停止后就直接退出,其余串口线程无法正常关闭,需要把退出操作挪到所有线程资源回收完成之后。
修复后的核心代码段如下:
def reader(self): """Reads data from the associated serial port and puts the data in a queue""" while self.alive: now = datetime.utcnow() line = self.serial.readline() # 过滤空内容、纯空白内容,兼容Python3 bytes类型 if len(line.strip()) == 0: continue # 字节转字符串,去掉末尾的串口换行符,忽略解码异常 line_str = line.decode('utf-8', errors='ignore').rstrip('\r\n') output_str = f"{now.time().isoformat()[:12]}(UTC) {self.name}> {line_str}" if COLOR and (self.color is not None): output_str = tc.colored(output_str, self.color) self.queue.put(output_str)
对应的KeyboardInterrupt分支修复后:
except KeyboardInterrupt: sys.stderr.write("\nQuitting\n") for term in terms: term.stop() term.join() sys.stdout.flush() sys.exit()
内容的提问来源于stack exchange,提问作者Manus
相关产品推荐
相关产品推荐

