在IEnumerable <byte> </byte>上执行FileStream的Write vs WriteByte

时间:2012-09-22 16:19:55

标签: .net performance stream bytearray filestream

我需要将IEnumerable<byte>的字节写入文件 我可以将它转换为数组并使用Write(byte[])方法:

using (var stream = File.Create(path))
    stream.Write(bytes.ToArray());

但由于IEnumerable未提供收藏品的项目数,因此不建议使用ToArray {。{3}}。

所以我可以在每次迭代中迭代IEnumerable并使用WriteByte(byte)

using (var stream = File.Create(path))
    foreach (var b in bytes)
        stream.WriteByte(b);

我想知道在写大量数据时哪一个会更快。

我想使用Write(byte[])根据数组大小设置缓冲区,因此在数组方面会更快。

我的问题是,当我只有IEnumerable<byte>有MB数据时,哪种方法更好?将它转换为数组并调用Write(byte[])或迭代它并为每个数组调用WriteByte(byte)

2 个答案:

答案 0 :(得分:3)

对大量字节流进行枚举是一个过程,会给通常很便宜的东西增加大量开销:将字节从一个缓冲区复制到下一个缓冲区。

通常情况下,LINQ样式的开销并不重要,但是当在普通硬盘驱动器上处理每秒1亿字节时,注意到严重的开销。这是过早优化。我们可以预见这将是一个性能热点,所以我们应该热切地优化。

因此,在复制字节时,您可能根本不应该依赖IEnumerableIList之类的抽象。绕过也包含ArraySegement<byte>Offset的数组或Count。这使您免于经常切片数组。

高吞吐量IO的一个原因就是每个字节调用一个方法。就像逐字节读和逐字节写一样。此会杀死性能,因为这些方法必须每秒调用数亿次。我亲身经历过。

始终一次处理至少4096字节的整个缓冲区。根据您正在使用哪种媒体进行IO,您可以使用更大的缓冲区(64k,256k甚至兆字节)。

答案 1 :(得分:1)

您应该分析哪个版本更快。 FileStream类有一个内部缓冲区,可以将Read()Write()方法与实际文件系统访问分开。

如果未在FileStream构造函数中指定缓冲区大小,则默认情况下它使用4096字节的缓冲区。该缓冲区将许多WriteByte()调用合并到一个写入底层文件中。唯一的问题是WriteByte()调用的开销是否会超过Enumerable.ToArray()调用的开销。后者肯定会使用更多的内存,但你总是需要处理这种权衡。

仅供参考:Enumerable.ToArray()的当前.NET 4实现涉及通过在必要时复制其大小来增长数组。每次增长时,都会复制所有值。此外,当所有项目都存储在数组中时,其内容将再次复制到最终大小的数组。对于实际实现IEnumerable<T>的{​​{1}}个实例,代码利用这个事实从正确的数组大小开始,然后让集合进行复制。