Python串口读取速度极慢,如何加速?

标签 python performance

我正在使用以下代码与数字万用表 (DMM) 通信。
它工作正常。我可以发送命令并读取结果。 我不使用 readline,因为我读取二进制数据。

问题:

问题是它非常非常慢。 用 Ruby 编写的相同代码要快得多。 当在 python 中需要 30 秒时,在 ruby​​ 中需要 2 或 3 秒(使用相同的速度)。 所以这不是硬件问题。
Ruby 代码和 Python 之间的唯一区别是,在 Python 中,我使用 inWaiting() 来读取所有可用的字符。在 Ruby 中,read() 函数会读取所有这些,而不仅仅是一个。

代码:

代码如下: 在 read_retry 函数中,我检查了我必须读取的字符数。 我读取它们,然后调用 data_is_ok 函数来检查它是否完成。
如您所见,返回的数据中嵌入了“\r”。 当最后一个字符为'\r'(没有更多数据可用)时,读取完成。
所以有一个循环来读取大量的 block 。

import serial
[...]

def data_is_ok(data):
  # No status code yet
  if len(data) < 2: return False

  # Non-OK status
  if len(data) == 2 and data[0] != "0" and data[1] == "\r": return True

  # Non-OK status with extra data on end
  if len(data) > 2 and data[0] != "0":
    raise ValueError('Error parsing status from meter (Non-OK status with extra data on end)')

  # We should now be in OK state
  if data[0] != "0" or data[1] != "\r":
    raise ValueError('Error parsing status from meter (status:%c size:%d)' % (data[0], len(data)))

  return len(data) >= 4 and data[-1] == "\r"

def read_retry():
  retry_count = 0
  data = ""

  while retry_count < 500 and not data_is_ok(data):
    bytesToRead = ser.inWaiting()
    data += ser.read(bytesToRead)
    if data_is_ok(data): return data
    time.sleep (0.001)
    retry_count += 1
  raise ValueError('Error parsing status from meter:  %c %d %r %r' % (data[0],len(data),data[1] == '\r', data[-1] == '\r'))

[...]

# Serial port settings
try:
  ser = serial.Serial(port='/dev/cu.usbserial-AK05FTGH', baudrate=115200, bytesize=8, parity='N', stopbits=1, timeout=5, rtscts=False, dsrdtr=False)
except serial.serialutil.SerialException, err:
  print "Serial Port /dev/cu.usbserial-AK05FTGH doesn't respond"
  print err
  sys.exit()

[...]

ser.write(cmd+'\r')
data = read_retry()

我使用过 cProfile 分析器。大部分时间都在time.sleep中度过

摘录如下:

         363096 function calls (363085 primitive calls) in 28.821 seconds

   Ordered by: internal time
   List reduced from 127 to 10 due to restriction <10>

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
    19050   25.245    0.001   25.245    0.001 {time.sleep}
        1    1.502    1.502    1.502    1.502 {posix.open}

问题:
是否可以使代码更快?

最佳答案

您可以做几件事。

你不应该需要 time.sleep()。如果你知道你只需要 2 个字节然后执行 ser.read(2) 如果你想限制等待时间 ser.timeout = 0.01 EDIT 除非你在一个单独的线程中。 Python 线程是贪婪的。 I/O 操作释放线程,以便主线程可以运行。但是,在您的情况下,您总是读取缓冲区 ser.read(ser.inWaiting()) 中的数据。我发现您需要强制串口等待 I/O ser.read(ser.inWaiting() + 32)。只需确保您也有超时,这样您就不会永远等待 I/O。此外,您当前的超时时间为 5 秒,等待时间很长。 结束编辑

您可以使用 readline ser.readline() 这可能只读到 '\r\n'。我不确定。

如果您使用的是 Python3,则 ser.read() 返回字节,因此任何比较都是错误的。 data[0] == '0' 需要是 data[0:1] == b'0'

另一件事是通过调试器运行代码,以确保您获得了预期的数据。可能是字符串比较或其他错误导致您不必要地循环了很多次。

关于Python串口读取速度极慢,如何加速?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47235381/

相关文章:

python - 中断(暂停)在 pdb 中运行 Python 程序?

python - 加快 Pandas 中自回归项的创建?

python - pandas:连接函数导致 NaN 值

java - 内存缓存和性能

java - Espresso : What are the advantages/disadvantages of having multiple tests vs. 一个用户旅程?

MySQL 评论

python - 为什么我的 python egg 不起作用? - 根本找不到分布

python - 使用 Keras、Python 纠正 CNN、基于 LSTM 的分类器的输入维度

c - 计算逻辑方程的最佳选择?

performance - 编译 F# 引用 : performance?