假设我正在编写一个 tcp 代理代码。我正在从传入流中读取并写入输出流。我知道 Stream.Copy 使用缓冲区,但我的问题是:Stream.Copy 方法是在从输入流中获取下一个块的同时写入输出流还是像“从输入中读取块,将块写入输出”这样的循环,从输入中读取块等”?
问问题
2945 次
4 回答
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);
}
}
如您所见,它从源读取,然后写入目标。这可能会得到改善;)
编辑:这是管道版本的可能实现:
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%)
所以它显然没有带来任何好处,这可能是它没有以这种方式实现的原因......
于 2012-09-15T22:17:55.293 回答
2
根据Reflector,它没有。这种行为最好记录在案,因为它会引入并发性。一般来说,这样做是不安全的。因此,不“管道”的 API 设计是合理的。
所以这不仅仅是一个Stream.Copy
或多或少聪明的问题。以并发方式复制不是实现细节。
于 2012-09-15T15:51:33.283 回答
0
Stream.Copy 是同步操作。我认为期望它使用异步读/写来进行同时读写是不合理的。
我希望异步版本(如RandomAccessStream.CopyAsync)使用同时读写。
注意:在复制过程中使用多个线程是不受欢迎的行为,但是使用异步读写同时运行它们是可以的。
于 2012-09-15T17:54:33.243 回答
-1
在获取下一个块时写入输出流是不可能的(当使用一个缓冲区时),因为获取下一个块可能会在缓冲区用于输出时覆盖缓冲区。
您可以说使用双缓冲,但它与使用双倍大小的缓冲区几乎相同。
于 2012-09-15T15:46:53.690 回答