C# CopyToAsync与ReadAsStreamAsync用于巨大的请求负载

C# CopyToAsync与ReadAsStreamAsync用于巨大的请求负载,c#,httpcontent,C#,Httpcontent,我必须为巨大的负载计算哈希,所以我使用流来不加载内存中的所有请求内容。问题是这两个代码之间有什么区别: using (var md5 = MD5.Create()) using (var stream = await authenticatableRequest.request.Content.ReadAsStreamAsync()) { return md5.ComputeHash(stream); } 那一个: using (var md5 = MD5.Create()) us

我必须为巨大的负载计算哈希,所以我使用流来不加载内存中的所有请求内容。问题是这两个代码之间有什么区别:

using (var md5 = MD5.Create())
using (var stream = await authenticatableRequest.request.Content.ReadAsStreamAsync())
{
    return md5.ComputeHash(stream);
}
那一个:

using (var md5 = MD5.Create())  
using (var stream = new MemoryStream())
{
    await authenticatableRequest.request.Content.CopyToAsync(stream);
    stream.Position = 0;

    return md5.ComputeHash(stream);
}
我在内心期待着同样的行为,但也许我遗漏了什么

我希望内部也会有同样的行为


为什么??我的意思是,在一种情况下,您必须将所有内容加载到内存中(因为猜猜看,您定义了一个内存流)。在另一种情况下不一定如此。

第一个版本看起来不错,让哈希程序处理流读取。它就是为此而设计的

ComputeHash(stream)
将读取while循环中的块,并重复调用TransformBlock()

但是第二段代码会将所有内容加载到内存中,所以不要这样做:

using (var stream = new MemoryStream())
{
    await authenticatableRequest.request.Content.CopyToAsync(stream);

第二个代码段不仅会将所有内容加载到内存中,而且会使用比HttpContent.ReadAsByteArrayAsync()更多的内存。


MemoryStream是一个流API,其初始大小为零。当数据写入时,缓冲区必须是原始缓冲区的两倍大。这会创建大量临时缓冲区对象,其大小超过最终内容

通过向
MemoryStream()
构造函数提供
capacity
参数,从一开始就分配最大预期缓冲区大小,可以避免这种情况

充其量,这将类似于调用:

var bytes = authenticatableRequest.request.Content.ReadAsByteArrayAsync();
return md5.ComputeHash(bytes);

您的第二个版本通过强制将全部内容保存在内存中而完全忽略了使用流的意义。MemoryStream是字节缓冲区之上的流API。如果不在构造函数中指定
容量
,则必须多次重新分配缓冲区。第二个代码段最终将使用比简单地以bytesSmall注释形式读取整个内容多得多的内存:这适用于当前版本的MemoryStream。但是没有理由说MemStream在使用链式块时不能遵循
List
。这可能只是因为需求不高。@bommelding列表即使在.NETCore中也是如此。至于MemoryStream,它是缓冲区上的包装器。另一种选择是新的System.IO.Pipelinenamespace@bommelding低分配的替代方案是新的System.IO.Pipeline命名空间,Marc Gravell在中解释了这一点。