如何使用大型文件 I/O(读取、写入)和计算优化例程
本文关键字:写入 计算 例程 优化 读取 大型 何使用 文件 | 更新日期: 2023-09-27 18:31:30
我知道他们说过早的优化是万恶之源......但就是那个时候。
我有一个缓慢但有效的过程,可以执行以下操作:
- 从 file.input 读取块(顺序)
- 转换区块
- 将转换后的块写入(追加)到文件输出
file.input 和 file.output 最终处于相同的大小 (10-100+ GB) 中。 一个块通常约为 10K。 转换步骤只是专有格式之间的转换。 为了讨论起见,我们可以认为它在计算上与实时压缩算法相当。
这些步骤当前在单个线程中完成。
我的问题:如何使其性能更好?
我意识到,基于正在处理的纯数据量,这永远不会变得"快速",但我必须相信有一些相对简单和标准的技术可以更快地做到这一点。
我尝试在阅读步骤(1)中添加缓冲。 也就是说,读取比块大小大得多的块并从缓冲区读取。 这很有帮助。 但是,我有点卡在转换步骤 (2) 和附加 (3) 是否可以执行任何
操作上。根据资源监视器,我的 CPU 使用率在 30-45% 之间波动,磁盘 I/O 有一些持续的低使用率。
我正在使用 C# 和一堆 P/调用到本机库的互操作。
您应该验证所有步骤是否占用了大部分时间 - 如果瓶颈结果只是一个步骤,我们在这里看错了图片。
磁盘 I/O 可能需要一段时间,在此期间 CPU 可用于其他任务,因此多线程解决方案可以提高性能。也许您可以使用一个线程来填充缓冲区多达 10 个可处理数据块,一个线程处理第一个加载的任何块,另一个线程仅写入已完成处理的任何块。然后,一对AutoResetEvents
可以通知每个线程前一个线程已完成处理一个或多个块。
首先,不要向此方案添加线程,它们不会提高性能。(当然,如果您的应用程序具有UI界面,则可以添加一个线程来执行密集型工作,并让用户继续执行其他任务)
其次,尝试最小化磁盘上的 IO。尽可能多地读取字节并写入所有切换器。第三,最好的选择可能是优化转型工作。
您的主要问题是 I/O。您在 2 个文件之间交替的事实使事情变得更糟。
- 缓冲读取和写入。大型操作更好,在这种情况下,操作越少越好。
由于还有一个 CPU 密集型部分,我会尝试使用线程。为了尽量减少等待,我会使用管道:ReaderThread -> Queue -> ProcescessingThread -> Queue -> WriterThread
如果您使用的是 .NET 4,则可以尝试 MemoryMappedFile 和 MemoryMappedViewAccessor
度量
- 1(简单的顺序读取到无处),
- 3(随机字节的简单顺序写入) 1
- +3(读取并立即复制大小合理的块 16K-64k-512k-1Mb)
- 2(只是计算)
然后看看你的数字,看看重叠是否可以带来任何相当大的好处。 45% 的 CPU 负载还不错,所以你最好保持原样。
你能得到的最好的是Max(1, 2, 3),所以相应地计划你的优化。