哎呀.BytesIO非常慢.选择?优化?



我正在带摄像头的Raspberry Pi上运行Python v3.5脚本。 该程序涉及从picamera录制视频并从视频流中获取样本帧以执行操作。 有时,处理字节缓冲区需要很长时间(20+ s)。 包含问题区域的代码的简化版本是:

import io
import picamera
camera = picamera.PiCamera()
camera.start_recording("/path/to/file.h264")
cnt = 0
while True:
if cnt > 30:
stream = io.BytesIO()
camera.capture(stream, use_video_port=True, resize=(1920, 1080), format='rgba')
cnt = 0
else:
cnt += 1

一段时间后,打开字节流所需的时间变得疯狂。 在我最近的一次运行中,一个实例花费了超过 48 秒! 此图显示了每个周期打开字节流的时间图。 我对代码问题区域中的每一行都进行了定时测试,我可以确认这是导致延迟的stream = io.BytesIO()行。

当我使用此任务期间使用psutils监控树莓派的 CPU 和内存时,我没有观察到明显的问题。 CPU 使用率为 10-15%,虚拟内存使用率为 ~24.2%,并且正在使用 0 交换。

除了 Python 程序之外,没有其他用户执行的进程在 Pi 上运行。 硬件正在运行带有GUI的默认Raspbian安装。

由于 Python 程序是 1000+ 行,因此我不打算在此问题文本中包含除最小示例之外的任何内容。 如果您想查看上下文信息,请查看带有代码的要点。

初步搜索表明这是 BytesIO 的已知问题。 Python 的一些旧错误跟踪(大约 2014 年)表明,在 3.5 版本中,这种情况在某些情况下得到了改进。

问题是:

  • 为什么这里的BytesIO慢?
  • 有没有另一种更快的字节流方法?
  • 有没有更好的方法来使用BytesIO来获得我需要的东西?

编辑:我在循环中添加了一行,强制流在每个进程结束时关闭stream.close(),但这似乎无效。 我仍然有 20+ 秒的流打开时间。

EDIT_2:我从编辑的信息中误读了测试中的值,错过了值具有科学记数法。

在循环中调用 BytesIO 时,必须手动关闭它。

在示例中,由于 Python 处理关闭字节流的方式,BytesIO 似乎很慢。 来自 BytesIO 的文档:

使用内存中字节缓冲区的流实现。它继承了 缓冲IOBase。当 close() 方法为 叫。

为什么大多数用户永远不会看到这个

字节缓冲区通常不会销毁,直到在退出时发出命令。 当 Python 脚本完成并解构环境时,iobase_exit会发出自动 close()(参见第 467 行)。 可以假设大多数用户只是在缓冲区中打开一个字节流,并在脚本完成之前将其保持打开状态。 也许这不是"最佳"方法,但这就是我见过的大多数实现io使用它的脚本的方式。

当重复调用新流而不关闭时,缓冲区似乎不断堆积,偶尔需要系统协商在内存限制处关闭它们。 Raspberry Pi的有限资源似乎加剧了这种情况。 这可以通过做一些花哨的事情来绘制缓冲区填满时的内存使用情况来衡量,但我在这里并不真正关心它,这超出了我的经验水平。

顺序使用 != 再入

如果稍后重新输入 SAME 缓冲区,则不应出现这种情况。 IO 类通过发出运行时错误来防止此边缘情况。 看这里。 这与我在原始问题中报告的情况不同,因为每次调用 BytesIO 时都会生成一个新的缓冲区。 讨论这一点是相关的,因为对文档这一部分的误解促成了问题中描述的事件。

OP中MWE的校正

import io
import picamera
camera = picamera.PiCamera()
camera.start_recording("/path/to/file.h264")
cnt = 0
while True:
if cnt > 30:
stream = io.BytesIO()
camera.capture(stream, use_video_port=True, resize=(1920, 1080), format='rgba')
stream.close()
cnt = 0
else:
cnt += 1

相关内容

  • 没有找到相关文章

最新更新