是流复制管道



假设我正在编写一个 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<T>(ref T x, ref T y)
{
    T tmp = x;
    x = y;
    y = tmp;
}

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

我运行了一些性能测试:

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

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

根据反射器,它没有。最好记录此类行为,因为它会引入并发性。一般来说,这样做从来都不安全。所以 API 设计不"管道"是合理的。

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

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

我希望异步版本(如RandomAccessStream.CopyAsync)使用同时读取和写入。

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

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

相关内容

  • 没有找到相关文章

最新更新