在不减慢线程速度的情况下保存大量数据
Posted
技术标签:
【中文标题】在不减慢线程速度的情况下保存大量数据【英文标题】:Saving large quantity of data without slowing a thread down 【发布时间】:2018-05-24 09:42:48 【问题描述】:我需要保存视频系统的痕迹,以便以后在 Windows 机器上进行检查重播。
帧生成是在线程中完成的,我想在处理函数结束时保存帧,例如
void generate_video_frame()
....
save_frame(frame);
为避免减慢生成线程save_frame
必须尽快完成此操作。最终目标是对视频进行磁盘保存跟踪。
每个帧都可能很大(甚至 20-30 MB),所以我不能将所有内容都存储在 RAM 中,因为我最终会完全填满它。
我想到了两个解决方案:
填充帧队列并使用另一个线程将其清空并将其刷新到磁盘(因此主线程不会受到影响)。如果刷新到磁盘线程较慢(如我所料),这最终也可能会填满 RAM
使用mapped file 并尽快写入每一帧
有没有更好的方法?如果没有,我应该注意哪些缺点/注意事项?
【问题讨论】:
异步写入文件 @RbMm 异步写入文件其中一个问题是错误处理 - 当有 50 个等待异步写入的待处理 IO 请求排队时,您如何干净地处理 IO 错误?另一个是管理在异步写入完成之前可能必须保持不变的数据缓冲区。正如 OP 所建议的那样,将框架对象放入写入线程的队列中可能要容易得多。 每个帧都可以很大(甚至 20-30 MB),所以我不能将所有内容都存储在 RAM 中,因为我最终会完全填满它。队列大小 - 一旦队列达到一定大小,让生产者线程阻塞,直到尝试添加到队列时队列大小下降。是的,它会减慢帧的生成速度,但最终您的帧生成速率受限于您写入磁盘的速度。 @AndrewHenle - 当然是处理。有多少待处理的 io 请求在这里根本不起作用 @RbMm 有多少挂起的io请求在这里根本不起作用 当然挂起的IO请求的数量起了作用。在异步写入完成之前,保存要写入的数据的内存缓冲区不能用于其他目的。缓冲区需要保留和跟踪,并且 OP 已经声明内存使用是一个考虑因素。 【参考方案1】:这取决于。你的框架的来源是什么?它们是否来自实时源(即相机),然后以某种方式进行处理?还是它们只是从任何类型的数据中生成的(并且没有来自数据源的实时压力)。
您的问题以某种方式暗示了后者。如果是这种情况,我建议确实在不同的线程中运行创建并写入磁盘。实际上,它可能还有更多,你可能不仅有两个任务,而是三个:
-
图像数据的生成
视频数据编码
将视频数据写入磁盘
第一个似乎不是你的瓶颈,所以我建议运行它并填满一个队列,直到你运行超过队列的某个限制(以避免耗尽 RAM)然后等待。
第二个,编码,压缩你的数据,以牺牲处理时间为代价。一旦图像在那里,这可以独立于生成来完成。这里有很多选择(从无损编解码器到具有不同质量的有损编解码器),但通常值得这样做。在此之后,您只能将压缩数据存储在 RAM 中,从而减少 RAM 使用量。另一方面,这当然会消耗一些处理能力,并且(假设它已经是多线程的)可能会减慢您的数据创建速度。因此,您可以在此处平衡数据大小与生成速度,以获得最佳平衡。
最后,写入磁盘。如果你写的是未压缩的数据,那就很多了。如果是压缩的,就没有那么多了。因为通常,写入磁盘有点慢,当然,写入更少的数据会有所帮助。此外,写入较大的数据块比写入少量数据更有效。因此,收集几帧并立即编写它们可能会节省您的时间。
这里有很多可以优化的地方。您的目标似乎是尽可能快地拥有整个系统。问题通常是何时投资工作来做到这一点。如果您正在开发的任何东西都在工作并且它只是关于性能,那么您可能会选择它。如果你只是关心这个,但你最终想做的事情还没有完成,我总是建议让它先运行,然后再快速运行。
【讨论】:
以上是关于在不减慢线程速度的情况下保存大量数据的主要内容,如果未能解决你的问题,请参考以下文章
如何在不减慢执行速度的情况下分析 Android 应用程序的执行?
如何使用 Python Ray 在不耗尽内存的情况下并行处理大量数据?