Python多线程监听双串口数据丢失问题排查与解决
串口双线程监听数据丢失问题的原因与解决办法
问题原因分析
- 普通列表非线程安全:你使用的
data_queue是普通Python列表,多线程同时调用append()和pop(0)时会触发数据竞争,比如两个线程同时追加数据可能导致元素覆盖、队列结构损坏,直接造成数据丢失。 - CPU资源抢占导致串口读取不及时:主线程的
while True忙轮询会占用大量CPU资源,使得串口监听线程得不到足够时间片去读取串口缓冲区数据,当缓冲区满溢后,新传入的数据就会被丢弃。 - 串口读取逻辑存在缺陷:如果
read_serial()是单次读取固定长度数据,或者未处理缓冲区剩余数据,线程频繁切换时会导致部分数据留在缓冲区未被读取,最终溢出丢失。
解决方案及优化代码
1. 核心优化点
- 用线程安全的
queue.Queue替代普通列表,避免多线程竞争问题。 - 主线程改用
queue.get()阻塞等待数据,不再占用多余CPU资源。 - 优化串口读取逻辑,确保及时清空缓冲区,避免数据残留。
优化后的完整代码
import threading import queue import serial # 假设使用pyserial库操作串口 # 初始化线程安全队列 data_queue = queue.Queue() def serial_listener(port, tag): # 根据设备实际参数配置串口 ser = serial.Serial(port=port, baudrate=9600, timeout=0.1) try: while True: # 读取缓冲区所有数据,避免残留 data = ser.read_all() if data: # 转码后加入队列(编码格式按需调整) data_queue.put([data.decode('utf-8'), tag]) except Exception as e: print(f"串口{port}异常: {e}") finally: ser.close() if __name__ == "__main__": # 创建守护线程,主线程退出时自动终止子线程 thread_usb0 = threading.Thread(target=serial_listener, args=('/dev/ttyUSB0', "1"), daemon=True) thread_usb1 = threading.Thread(target=serial_listener, args=('/dev/ttyUSB1', "2"), daemon=True) thread_usb0.start() thread_usb1.start() # 主线程阻塞等待队列数据,无需忙轮询 while True: new_data = data_queue.get() # 无数据时自动阻塞,不占用CPU print("*****New data has arrived.*****") print(new_data) if new_data[1] == "1": # 执行串口1的后续处理逻辑 pass elif new_data[1] == "2": # 执行串口2的后续处理逻辑 pass else: print("未知端口标签")
额外注意事项
- 确保串口参数(波特率、奇偶校验、数据位等)与设备端完全一致,参数不匹配也会导致数据乱码或丢失。
- 若数据量极大,可设置队列最大容量(
queue.Queue(maxsize=N)),避免内存占用过高。 - 不要使用
join()阻塞主线程,你的场景下守护线程的方式更适配主线程持续运行的需求。
内容的提问来源于stack exchange,提问作者pretty_juvenile
相关产品推荐
相关产品推荐

