CPU 负载 python 串行读取

CPU load of python serial read

我有一个应用程序需要从 Python 中的线程中的串行端口读取数据。因为它被放置在一个线程中,所以我可以使用:

timeout = None

并在线程中使用以下代码:

# Setup
ser = serial.Serial(port, 38400, timeout = None)

# Loop
data = ser.read(2)
if data[0] == 2:
    data += ser.read(data[1]-2) # Expected length of message
    return data
else: # Handle error message

然而,当我将它与其他线程的频率进行比较时,我通过使用以下方式获得了将近 200% 的频率增加:

# Setup
ser = serial.Serial(port, 38400, timeout = 0)

# Loop
data = ser.read(1)
if data and data[0] == 2:
    while len(data) < 2:
        data += ser.read(1)
    while len(data) < data[1]:
        data += ser.read(1)
    return data
else: # Handle error message

此外,在模拟过程中收集数据,然后 "replayed" 使用套接字代替,使用套接字时我得到了更好的结果,让我相信我应该能够增加应用程序的整体频率甚至是实时的。但是我在 Python.

中找不到任何关于串行读取时间复杂度的相关讨论

编辑:

经过进一步的修补和测试,我仍然无法找出读取串口的最佳方法...是否有任何"correct"关于读取串口的最佳方法的时间问题的答案复杂度是?

// 雅各布

尝试强制串口等待 I/O ser.read(ser.inWaiting() + 32)

我看到 serial_port.read(serial_port.in_waiting) 读取速度非常快,它避免了缓冲区中字节累积的问题

如果您在 Python3 上,则 ser.read() returns 字节,因此任何比较都是错误的。调试:data[0] == 2 需要是 data[0:1] == b'2'

一起玩:

ser = serial.Serial(port, 38400)
while(True):        
    print('ser_is_open')
    ser.read(ser.in_waiting() + 32)                   
    print('ser_in_waiting')

没有足够的信息来确切知道发生了什么,但您似乎正在尝试接收采用以下形式之一的消息:

  • “数据”消息,如下所示:| 2 | Length | d1 | d2 | ... | dN |
  • 一些错误指示...您没有提到,但也许只是一个不是 2 的字节?

在您的第一个实现中,行 data = ser.read(2) 将“永远等待,直到至少收到两个字节”。但是如果发送单个 1 字节的消息,那么代码将一直等待直到收到另一条消息。

虽然没有“正确”的方式从串行端口读取,但您可能想尝试将字节接收和消息解析分开。

例如,您可能有这样的东西:

from collections import deque


def receive_bytes(ser, buffer):
    """Read bytes from serial port and append them to the buffer"""
    data = ser.read(1)
    while data:
        buffer.append(data[0])
        data = ser.read(1)


def consume_messages(buffer):
    """Consume available messages from the buffer destructively"""

    # This loop uses the first byte as the key for what
    # message should be in the buffer. We only consume
    # a message from the buffer when it is present in
    # its entirety (i.e. we only read a data mesage once
    # all the bytes are present).
    messages = []
    while len(buffer) > 0:
        # Check if we have a data message
        if buffer[0] == 2 and len(buffer) > 1:
            data_message_len = buffer[1]
            if len(buffer) - 2 > data_message_len:
                # looks like enough info for a data message
                buffer.popleft()  # the 2 byte
                buffer.popleft()  # the length byte
                data_message = [
                    buffer.popleft() for _ in range(data_message_len)
                ]
                messages.append(data_message)

        # Check if we have a "1" message
        elif buffer[0] == 1:
            messages.append(buffer.popleft())

        else:
            # looks like the first byte is something we don't
            # know about...likely a synchronization error, so just
            # drop it
            buffer.popleft()

    return messages


def handle_messages(messages):
    for m in messages:
        print(m)


if __name__ == "__main__":
    # setup
    ser = serial.Serial(port, 38400, timeout=0)
    buf = deque()

    # loop
    while True:
        receive_bytes(ser, buf)
        messages = consume_messages(buf)
        handle_messages(messages)

FWIW,我认为时间复杂度与此无关。原始代码的阻塞性以及您的应用程序代码、串行库和底层之间的交互 ​​OS 都是比时间复杂度更大的因素。

基本上...您的计算机比控制串行端口的硬件快得多,因此采用阻塞等待方法通常会比没有超时的检查浪费更多的计算时间 - 即使您正在检查 thousands/millions 字节之间的次数。