我正在开发一个控制台应用程序,它将端点列表添加到视频数据中,发出HTTP请求,并将结果保存到文件中。这些是相对较小的视频。由于我无法控制的问题,其中一个视频非常大(145分钟而不是几秒钟)。
我看到的问题是,在调用该请求后,我的内存使用率达到~1 GB,并且我最终得到“任务被取消”错误(可能是因为客户端超时)。这很好,我不想要这个视频,但令人担忧的是,无论我做什么,我分配的内存都会保持很高。我希望能够释放内存。似乎有点关于任务管理器在此调用之前显示大约14 MB的内存使用量,然后继续逐渐涓流。在VS调试器中,我只看到一个尖峰。
我尝试将所有内容都放在using
语句中,重新初始化HttpClient
异常,手动调用GC.Collect()
而没有运气。我正在使用的代码看起来像这样:
consumer.Received += async (model, ea) =>
{
InitializeHttpClient(source);
...
foreach(var item in queue)
{
await SaveFileFromEndpoint(url, fileName);
...
}
}
和方法:
public void InitializeHttpClient(string source)
{
...
_client = new HttpClient();
...
}
public async Task SaveFileFromEndpoint(string endpoint, string fileName)
{
try
{
using (HttpResponseMessage response = await _client.GetAsync(endpoint))
{
if (response.IsSuccessStatusCode)
{
using(var content = await response.Content.ReadAsStreamAsync())
using (var fileStream = File.Create($"{fileName}"))
{
await response.Content.CopyToAsync(fileStream);
}
}
}
}
catch (Exception ex)
{
}
}
以下是我的调试器输出:
我想我对我所看到的内容有几个问题:
提前感谢您的帮助!
答案 0 :(得分:5)
如果您使用HttpClient.SendAsync(HttpRequestMessage, HttpCompletionOption)
代替GetAsync
,则可以提供HttpCompletionOption.ResponseHeadersRead
,(而不是默认ResponseContentRead
)。这意味着响应流将在响应主体下载之前(而不是之后)回传给您,并且需要的缓冲区要少得多。
答案 1 :(得分:2)
除了@spender的答案(很明确)之外,您还需要确保在完成响应后将其处置。您可以在"Efficiently Streaming Large HTTP Responses With HttpClient"文章中找到有关此信息的更多信息。
这是一个代码示例:
using (HttpClient client = new HttpClient())
{
const string url = "https://github.com/tugberkugurlu/ASPNETWebAPISamples/archive/master.zip";
using (HttpResponseMessage response = await client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead))
using (Stream streamToReadFrom = await response.Content.ReadAsStreamAsync())
{
string fileToWriteTo = Path.GetTempFileName();
using (Stream streamToWriteTo = File.Open(fileToWriteTo, FileMode.Create))
{
await streamToReadFrom.CopyToAsync(streamToWriteTo);
}
}
}
您还需要考虑到不应为每个操作创建一个HttpClient
实例。 HttpClientFactory
是一种井井有条的方式,可确保以最高效的方式安全地在应用程序中流动HttpClient。