是Stream.Copy管道吗?

Isr*_*Lot 7 c# tcp stream

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

Tho*_*que 6

这是CopyTo.NET 4.5中的实现:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

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


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

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<T>(ref T x, ref T y)
{
    T tmp = x;
    x = y;
    y = tmp;
}
Run Code Online (Sandbox Code Playgroud)

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

我运行了一些性能测试:

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

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


Dan*_*ani -1

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

  • 由于(正如您自己所注意到的)我们可以使用单独的缓冲区(或缓冲区片段),因此这显然不是“不可能”。 (3认同)