CopyToAsync 与 ReadAsStreamAsync 的巨大请求负载

CopyToAsync vs ReadAsStreamAsync for huge request payload

我必须为巨大的负载计算散列,所以我使用流不加载内存中的所有请求内容。问题是这段代码有什么区别:

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);
}

我希望在内部有相同的行为,但也许我遗漏了什么。

I expect the same behavior internally,

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

第一个版本看起来不错,让散列器处理流读取。它就是为此而设计的。

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

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

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

第二个片段不仅会将所有内容加载到内存中,而且会比 HttpContent.ReadAsByteArrayAsync().

使用 更多 内存

MemoryStream 是一个 Stream API 在 byte[] buffer whose initial size is zero. As data gets written into it, the buffer has to be reallocated 上进入一个比原始缓冲区大两倍的缓冲区。这可以创建一个 lot 大小超过最终内容的临时缓冲区对象。

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

充其量,这类似于调用:

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