Flask多线程读取USB RFID阅读器时出现PySerial并发异常
问题分析与解决办法
核心问题:Flask多进程导致串口资源冲突
你遇到的SerialException本质是多个进程同时访问同一个USB串口设备。Flask默认的开发服务器(Werkzeug)在debug模式下会启动多个进程(通常是2个),每个进程都会执行start_reader(),从而创建独立的线程去打开/dev/ttyUSB0,这就导致了串口设备的并发访问冲突,引发"设备报告可读但无数据返回"的异常。
而你测试无线程时功能正常,是因为此时整个Flask进程只有一个串口连接,没有冲突;单独的测试脚本也是单进程,所以没问题。
快速解决方案:强制Flask使用单进程模式
修改Flask的启动代码,明确指定单进程、单线程运行:
if __name__ == '__main__': app.run(debug=True, threaded=False, processes=1)
或者在命令行启动时加上参数:
flask run --without-threads --debug
代码优化建议
除了进程冲突问题,你的代码还有几个可以优化的点,避免后续的错误:
正确处理空数据,避免int转换异常
当串口超时返回空字符串时,直接跳过后续的解析逻辑,不要执行data[2:]和int(clean,16):with ser_lock: data = ser.readline().decode().strip() if not data: print("No data read!") continue # 后续解析逻辑放在这里,确保data非空确保串口资源正确释放
在serial_data函数中,添加finally块关闭串口,防止进程退出时资源泄漏:try: ser = serial.Serial(port=PORT, baudrate=BAUD, timeout=2) while True: # 读取逻辑... except Exception as e: print("Error opening port: " + str(e)) finally: if ser and ser.is_open: ser.close() print("Serial port closed.")移除不必要的线程锁
因为你只启动了一个线程来处理串口读取,且在单进程模式下没有并发访问串口的情况,所以ser_lock是多余的,可以直接删除,简化代码。
进阶权限优化(可选)
为了避免每次重启系统都要手动执行sudo chmod a+rw /dev/ttyUSB0,可以添加udev规则永久设置串口权限:
- 创建规则文件:
sudo nano /etc/udev/rules.d/99-rfid.rules - 写入内容(替换为你的读卡器VendorID和ProductID,可通过
lsusb命令查看):SUBSYSTEM=="tty", ATTRS{idVendor}=="xxxx", ATTRS{idProduct}=="xxxx", MODE="0666" - 重启udev服务生效:
sudo udevadm control --reload-rules && sudo udevadm trigger
内容的提问来源于stack exchange,提问作者jrbobdobbs83
相关产品推荐
相关产品推荐

