结合FileStream和MemoryStream以避免磁盘访问/分页,同时接收千兆字节的数据?

时间:2013-10-30 15:38:22

标签: c# .net memory-management filestream memorystream

我收到一个文件作为byte []数据包流(总大小未提前知道),我需要在收到它之后立即处理它(我无法进行处理)在飞行中)。收到的文件总大小可以从10 KB到4 GB不等。

  • 用于存储接收数据的一个选项是使用MemoryStream,即MemoryStream.Write(bufferReceived, 0, count)个调用序列来存储接收到的数据包。这很简单,但显然会导致大文件的内存不足。
  • 另一种选择是使用FileStream,即FileStream.Write(bufferReceived, 0, count)。这样,不会出现内存不足异常,但我不确定的是由于磁盘写入导致的性能不佳(只要仍有大量内存可用,我不想发生) - 我想要尽可能避免磁盘访问,但我不知道如何控制它。

我做了一些测试,大部分时间,似乎在MemoryStream.Write()FileStream.Write()的连续10次调用之间几乎没有性能差异,但很多似乎依赖于缓冲区大小和有问题的数据总量(即写入次数)。显然,MemoryStream大小的重新分配也是一个因素。

  1. 使用MemoryStreamFileStream的组合是否有意义,即默认情况下写入内存流,但一旦收到的数据总量超过,例如500 MB,写入FileStream;然后,从两个流中读取块以处理接收的数据(首先从MemoryStream处理500 MB,处理它,然后从FileStream读取)?

  2. 另一种解决方案是使用不需要连续地址空间进行内部数组分配的自定义内存流实现(即内存流的链表);这样,至少在64位环境中,内存不足异常应该不再是问题。骗局:额外的工作,更多的错误空间。

  3. 那么FileStream vs MemoryStream读取/写入在磁盘访问和内存缓存方面的表现如何,即数据大小/性能平衡。我希望只要有足够的RAM可用,FileStream无论如何都会从内存(缓存)内部读/写,虚拟内存会处理剩下的事情。但我不知道FileStream在写入时会显式访问磁盘的频率。

    任何帮助都将不胜感激。

3 个答案:

答案 0 :(得分:5)

不,试图优化这一点没有任何意义。 Windows本身已经缓存文件写入,它们由文件系统缓存缓冲。所以你的测试是准确的,MemoryStream.Write()和FileStream.Write()实际写入RAM并没有明显的性能差异。文件系统驱动程序懒惰地在后台将其写入磁盘。

用于文件系统缓存的RAM是在进程声称其RAM需要之后剩下的。通过使用MemoryStream,您可以降低文件系统缓存的有效性。或者换句话说,你在没有利益的情况下换取另一个。事实上你的情况更糟,你使用 RAM。

没有帮助,这已经在操作系统内进行了大量优化。

答案 1 :(得分:3)

由于Windows的最新版本默认启用write caching,因此我建议您只需使用FileStream并让Windows管理何时或是否实际写入物理硬盘驱动器。

如果这些文件在收到后仍未存在,您应该将文件写入a temp directory并在完成后删除它们。

答案 2 :(得分:3)

使用允许您定义缓冲区大小的FileStream constructor。例如:

using (outputFile = new FileStream("filename", 
    FileMode.Create, FileAccess.Write, FileShare.None, 65536))
{
}

默认缓冲区大小为4K。使用64K缓冲区可减少对文件系统的调用次数。较大的缓冲区将减少写入次数,但每次写入开始需要更长时间。经验数据(多年使用这些东西)表明64K是一个非常好的选择。

正如其他人所指出的那样,文件系统可能会进行进一步的缓存,并在后台进行实际的磁盘写入。您将数据写入FileStream的速度非常快,您收到数据的速度极快。