是Stream.Copy管道吗?

假设我正在编写tcp代理代码。 我正在读取传入的流并写入输出流。 我知道Stream.Copy使用缓冲区,但我的问题是:Stream.Copy方法在从输入流中获取下一个块时是否写入输出流,或者它是一个循环,如“从输入读取块,将块写入输出,从输入中读取块等“?

这是.NET 4.5中CopyTo的实现:

 private void InternalCopyTo(Stream destination, int bufferSize) { int num; byte[] buffer = new byte[bufferSize]; while ((num = this.Read(buffer, 0, buffer.Length)) != 0) { destination.Write(buffer, 0, num); } } 

如您所见,它从源读取, 然后写入目标。 这可能会改善;)


编辑:这是一个管道版本的可能实现:

 public static void CopyToPiped(this Stream source, Stream destination, int bufferSize = 0x14000) { byte[] readBuffer = new byte[bufferSize]; byte[] writeBuffer = new byte[bufferSize]; int bytesRead = source.Read(readBuffer, 0, bufferSize); while (bytesRead > 0) { Swap(ref readBuffer, ref writeBuffer); var iar = destination.BeginWrite(writeBuffer, 0, bytesRead, null, null); bytesRead = source.Read(readBuffer, 0, bufferSize); destination.EndWrite(iar); } } static void Swap(ref T x, ref T y) { T tmp = x; x = y; y = tmp; } 

基本上,它同步读取一个块,开始异步复制到目标,然后读取下一个块并等待写入完成。

我运行了一些性能测试:

  • 使用MemoryStream ,我没想到会有显着的改进,因为它不使用IO完成端口(AFAIK); 事实上,表现几乎相同
  • 使用不同驱动器上的文件,我预计管道版本的性能会更好,但实际上并没有…它实际上稍慢(5到10%)

所以它显然没有带来任何好处,这可能是它没有以这种方式实现的原因……

根据Reflector它没有。 这种行为最好记录下来,因为它会引入并发性。 一般来说,这绝不是安全的。 因此,不“管道”的API设计是合理的。

所以这不仅仅是Stream.Copy或多或少聪明的问题。 以并发方式复制不是实现细节。

Stream.Copy是同步操作。 我认为期望它使用异步读/写来同时进行读写是不合理的。

我希望asynchrounous版本(如RandomAccessStream.CopyAsync )可以同时使用读写。

注意:在复制期间使用多个线程将是不受欢迎的行为,但使用异步读取和写入同时运行它们是可以的。

在获取下一个块时,写入输出流是不可能的(当使用一个缓冲区时),因为获取下一个块可以在用于输出时覆盖缓冲区。
你可以说使用双缓冲,但它几乎与使用双倍大小的缓冲区相同。