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

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

代码优化建议

除了进程冲突问题,你的代码还有几个可以优化的点,避免后续的错误:

  1. 正确处理空数据,避免int转换异常
    当串口超时返回空字符串时,直接跳过后续的解析逻辑,不要执行data[2:]和int(clean,16):

    with ser_lock:
        data = ser.readline().decode().strip()
    if not data:
        print("No data read!")
        continue
    # 后续解析逻辑放在这里,确保data非空
    
  2. 确保串口资源正确释放
    在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.")
    
  3. 移除不必要的线程锁
    因为你只启动了一个线程来处理串口读取,且在单进程模式下没有并发访问串口的情况,所以ser_lock是多余的,可以直接删除,简化代码。

进阶权限优化(可选)

为了避免每次重启系统都要手动执行sudo chmod a+rw /dev/ttyUSB0,可以添加udev规则永久设置串口权限:

  1. 创建规则文件:sudo nano /etc/udev/rules.d/99-rfid.rules
  2. 写入内容(替换为你的读卡器VendorID和ProductID,可通过lsusb命令查看):
    SUBSYSTEM=="tty", ATTRS{idVendor}=="xxxx", ATTRS{idProduct}=="xxxx", MODE="0666"
    
  3. 重启udev服务生效:sudo udevadm control --reload-rules && sudo udevadm trigger

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 09:37:46