MSDN 网站指出:
缓冲区是内存中用于缓存数据的字节块,从而减少了对操作系统的调用次数。缓冲区提高了读写性能。缓冲区可以用于读取或写入,但不能同时用于两者。BufferedStream 的 Read 和 Write 方法会自动维护缓冲区。
我应该在每一个可能的场合使用这个类吗?
MSDN 网站指出:
缓冲区是内存中用于缓存数据的字节块,从而减少了对操作系统的调用次数。缓冲区提高了读写性能。缓冲区可以用于读取或写入,但不能同时用于两者。BufferedStream 的 Read 和 Write 方法会自动维护缓冲区。
我应该在每一个可能的场合使用这个类吗?
根据布拉德艾布拉姆斯的说法,几乎从不:链接
不,将 BufferedStream 包装在 FileStream 周围的好处为零。大约 4 年前,我们将 BufferedStream 的缓冲逻辑复制到 FileStream 中,以鼓励更好的默认性能......事实上,我认为 .NET Framework 中没有任何 Streams 需要它,但自定义 Stream 实现可能需要它,如果他们默认不做缓冲。
以下是我正在学习的在线课程中的一些文字:
BufferedStream 类是一个扩展 Stream 类的具体类,用于为另一种类型的流(同步和异步)提供额外的内存缓冲区。创建类的实例时,必须将 BufferedStream 类配置为读取或写入,但不能将 BufferedStream 配置为同时执行这两项任务。
Microsoft 通过包含一个内置缓冲区提高了 .NET Framework 中所有流的性能。通过将 BufferedStream 应用于现有流(例如 FileStream 或 MemoryStream),性能显着提高。将 BufferedStream 应用到现有的 .NET Framework 流会产生双缓冲区。
BufferedStream 类最常见的应用是在不包含内置缓冲区的自定义流类中。
我知道的最好的情况是 BinaryFormatter 直接从 NetworkStream 序列化/反序列化。在中间使用 BufferedStream 可将性能提高十倍。
普通文件 I/O 流已经使用 StreamReader/StreamWriter 进行缓冲。
由于对流的读/写操作,通常使用带字节数组的读/写方法,你自然会自己提供一些缓冲。
如果您使用非常小的数组或使用 WriteByte,则可以通过在两者之间使用 BufferedStream 获得更好的性能。
迟到的答案,但无论如何都会回答。如果您了解它的工作原理,您就可以理解为什么在某些情况下使用它没有意义,以及为什么在其他情况下不使用它是有意义的。
为了证明这一点,我正在使用StreamWrapper
类。只用这个类来看看你打断点的次数!在这个类中放置断点。我们的目标是查看调用 Write、Read 和其他方法的次数。
// This class is only used for demo purposes. Place a breakpoint on all parts
class StreamWrapper : Stream
{
Stream stream;
public StreamWrapper(Stream s)
{
stream = s;
}
public override bool CanRead => stream.CanRead;
public override bool CanSeek => stream.CanSeek;
public override bool CanWrite => stream.CanWrite;
public override long Length => stream.Length;
public override long Position { get => stream.Position; set => stream.Position = value; }
public override void Flush()
{
stream.Flush();
}
public override int Read(byte[] buffer, int offset, int count)
{
return stream.Read(buffer, offset, count);
}
public override long Seek(long offset, SeekOrigin origin)
{
return stream.Seek(offset,origin);
}
public override void SetLength(long value)
{
stream.SetLength(value);
}
public override void Write(byte[] buffer, int offset, int count)
{
stream.Write(buffer, offset, count);
}
}
现在您已经拥有了基本上是现有 strem 的包装器的包装器类,您可以进行以下测试:
示例写作:
// in real life you want this to be larger.
int bufferSize = 8;
// Use BufferedStream to buffer writes to a MemoryStream.
using (var memory_test = new StreamWrapper(new MemoryStream()))
using (BufferedStream stream = new BufferedStream(memory_test, bufferSize))
{
// all this will only send one write to memory_test!
stream.Write(new byte[] { 1, 2 });
stream.Write(new byte[] { 1, 2 });
stream.Write(new byte[] { 1, 2 });
stream.Write(new byte[] { 1, 2 });
// BREAKPOINT ONLY HITS ONE TIME
// All this will also send only one write to memory_test
for (int i = 0; i < 8; i++)
stream.WriteByte(5);
// BREAKPOINT ONLY HITS ONE TIME AGAIN INSTAD OF 8
// this will send one write to memory_test. Writes of more than 8 bytes can happen!
stream.Write(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18 });
// ALL THIS WILL SEND ONE WRITE AGAIN
}
示例阅读:
// example reading
{
// create stream with some data in it that we will be reading
var ms = new MemoryStream();
{
// Write 256 bytes
for (int i = 0; i <= byte.MaxValue; i++)
{
ms.WriteByte((byte)i);
}
ms.Position = 0;
}
// Use BufferedStream to buffer writes to a MemoryStream.
using (var memory_test = new StreamWrapper(ms))
{
using (BufferedStream stream = new BufferedStream(memory_test, 8))
{
// note I do not care about the output of each read for demo breakpoint. On real life you will store that output
// for now we only care how many times we hit the breakpoint because on real life that could be a slow/expensive
// operation such as opening a file for writing and you want to do those as few as possible.
// hit breakpoint only one time with all this reads
stream.ReadByte();
stream.ReadByte();
stream.ReadByte();
stream.ReadByte();
stream.ReadByte();
stream.ReadByte();
stream.ReadByte();
stream.ReadByte();
// hit breakpoint only one time with all this reads
stream.Read(new byte[2] );
stream.Read(new byte[2] );
stream.Read(new byte[2] );
stream.Read(new byte[2] );
// hit breakpoint only one time even though it is larger than our buffer size 8
// our goal is to hit the breakpoint as fewest time as possible because in real life
// this could be slow/expensive operations
stream.Read(new byte[1024] );
}
}
}
例如,如果这是对文件的写入操作,则可以通过确保始终一次写入至少 8 个字节而不是 1 个字节来提高性能。在现实生活中,您希望这个数字约为 4 KB
在每一个可能的场合都必须使用的是常识。在从 MemoryStream 读写时使用此类没有用处,但在进行网络或磁盘 IO 时它可能非常有用(如果这些子系统的 Streams 不自己进行缓冲)。