python串行读取的CPU负载
Posted
技术标签:
【中文标题】python串行读取的CPU负载【英文标题】:CPU load of python serial read 【发布时间】:2020-06-11 09:43:15 【问题描述】:我有一个应用程序,我需要从 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
此外,在模拟过程中,数据被收集,然后使用套接字“重放”,当使用套接字时,我得到了更好的结果,让我相信我应该能够提高整体频率该应用程序甚至是实时的。但是我找不到任何关于 Python 中串行读取时间复杂度的相关讨论。
编辑:
经过进一步的修补和测试,我仍然无法找出读取串行端口的最佳方法......关于时间复杂度读取串行端口的最佳方法是否有任何“正确”答案?
// 雅各布
【问题讨论】:
你确定数据的结尾是可靠的吗?我总是等待一个特殊字符,因为在串行通信期间总是会超时 【参考方案1】:没有足够的信息来确切地知道发生了什么,但您似乎正在尝试接收采用以下形式之一的消息:
“数据”消息,如下所示:| 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,我认为时间复杂度与此无关。原始代码的阻塞特性以及应用程序代码、串行库和底层操作系统之间的交互都是比时间复杂度更大的因素。
基本上...您的计算机比控制串行端口的硬件快得多,因此与没有超时的检查相比,使用阻塞等待方法通常会浪费更多的计算时间 - 即使您正在检查数千/数百万字节之间的时间。
【讨论】:
我对复杂性有同样的想法,但是在模拟过程中我使用内部套接字而不是串行端口,并且使用内部套接字时应用程序的更新频率要高得多。而且由于大多数应用程序都受 CPU 限制,这表明 CPU 读取串行端口会产生一些负载。 我猜是好点,但可能是底层操作系统检查其网络堆栈以查看是否有 2 个字节可用,而不是检查您的串行硬件(这可能是USB上的串行端口仿真器对吗?)。如果您只要求 1 个字节,如果您发现阻塞检查之间的差异会很有趣。 我使用的是 USB 串口。该应用程序是自动叉车的实时导航系统,通过串行端口发送数据的传感器是车轮编码器【参考方案2】:尝试强制串口等待 I/O ser.read(ser.inWaiting() + 32)
我看到 serial_port.read(serial_port.in_waiting) 读取速度非常快,它避免了缓冲区中字节累积的问题
如果你在 Python3 上,那么 ser.read() 返回字节,所以任何比较都是错误的。调试: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')
【讨论】:
在这种情况下,串行 I/O 是一个轮式编码器,如果将多个消息堆叠在缓冲区中,那么读取多个消息似乎是个坏主意。我正在使用 python 3,data[0] == 2
效果很好......以上是关于python串行读取的CPU负载的主要内容,如果未能解决你的问题,请参考以下文章
Linux服务器CPU内存磁盘空间负载情况查看python脚本
【Linux】Linux系统下简单模拟高CPU\高内存\高负载的方法