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

PySerial多进程/客户端同时访问串口设备的机制与最佳实践

多进程访问USB-RS485电表设备的最佳实践

为什么多进程能同时打开串口?

不同操作系统对串口设备的独占性处理逻辑不一样:Linux默认允许多个进程打开同一个串口设备,而Windows通常会强制独占访问。你遇到的情况应该是在Linux类系统下,内核没阻止多进程打开,但这绝对不是安全操作——两个进程同时读写会直接导致数据混乱:比如A进程发的请求,B进程的readline()可能截走响应;或者两个进程的发送字节混在一起,电表根本无法解析命令。

频繁打开/关闭上下文管理器是否合理?

  • 短期能用,但绝非最优:每次打开串口都会重置波特率、奇偶校验等参数,如果其他进程也在操作,很容易互相干扰参数设置。
  • 额外开销:部分驱动下,频繁开关会触发USB设备重新枚举,增加延迟,次数多了还可能导致设备假死。
  • 建议:除非必要,尽量保持一个长期有效的串口连接,用同步机制控制访问。

同时开启多个上下文(多进程打开串口)可行吗?

完全不可行,属于高危操作:

  • 数据冲突:多进程同时发命令,电表收到的是混杂字节流,无法正确解析;返回的响应也会被多个进程争抢,结果全是错乱的。
  • 硬件风险:部分RS485芯片在多进程同时驱动下,可能出现收发引脚状态冲突,长期这么搞可能损坏设备。

实现“随时可用的读数函数”的最优方案

核心逻辑是让单个进程/线程独占串口,其他请求通过同步机制排队访问,以下是两种落地方式:

方式1:单守护进程 + 进程间通信(适合多进程场景)

  1. 启动一个单独的守护进程,独占打开串口并保持连接。
  2. 其他需要读数的进程通过队列、管道或本地socket向守护进程发请求。
  3. 守护进程收到请求后,执行get_values_str发命令、读响应,再把结果返回给请求方。
    示例代码片段:
# 守护进程代码(serial_daemon.py)
import serial
from multiprocessing import Process, Queue

def serial_worker(request_queue, response_queue):
    # 独占打开串口,长期保持连接
    with serial.Serial('/dev/ttyUSB0', 9600, timeout=2) as ser:
        while True:
            cmd = request_queue.get()
            if cmd == 'GET_VALUES':
                ser.write(get_values_str)
                resp = ser.readline()
                response_queue.put(resp)
            elif cmd == 'EXIT':
                break

if __name__ == '__main__':
    req_q = Queue()
    resp_q = Queue()
    daemon = Process(target=serial_worker, args=(req_q, resp_q))
    daemon.start()
# 客户端进程调用代码
from multiprocessing import Queue
import serial_daemon

def get_meter_data():
    serial_daemon.req_q.put('GET_VALUES')
    return serial_daemon.resp_q.get()

方式2:单进程内多线程 + 线程锁(适合单进程多任务场景)

如果所有读数逻辑都在同一个进程里,用线程锁控制串口访问:

  1. 全局维护一个串口对象和threading.Lock实例。
  2. 每次调用读数函数时,先获取锁,再执行读写操作,完成后自动释放锁。
    示例代码:
import serial
import threading

# 全局串口对象和锁
ser = serial.Serial('/dev/ttyUSB0', 9600, timeout=2)
serial_lock = threading.Lock()

def get_meter_data():
    # 用with自动管理锁的获取和释放
    with serial_lock:
        ser.write(get_values_str)
        return ser.readline()

额外注意事项

  • 串口参数必须统一:所有访问串口的代码要用完全相同的波特率、奇偶校验、停止位等参数,否则直接通信失败。
  • 合理设置超时:读写操作时设置合适的超时时间,避免进程/线程因等待响应挂起。
  • 异常捕获:添加串口断开、读写失败的异常处理,比如守护进程检测到断开时自动重连。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 10:25:35