我一直在嘗試解決在我的應用程式中下載一批影像時遇到的問題。
如果我HttpClient.GetStreamAsync(url)用來下載批處理,那么似乎某些請求會超時,并最終出錯。
但是,如果我使用HttpClient.GetAsync(url),則整個批次將毫無問題地下載。
我懷疑這與呼叫時沒有釋放埠有關.GetStreamAsync(url),但是我可能是在胡說八道。
下面是演示該問題的代碼片段。
async Task Main()
{
HttpClient httpclient = new HttpClient();
var imageUrl = "https://tenlives.com.au/wp-content/uploads/2020/09/Found-Kitten-0-8-Weeks-Busy-scaled.jpg";
var downloadTasks = Enumerable.Range(0, 15)
.Select(async u =>
{
try
{
//Option 1) - this will fail
var stream = await httpclient.GetStreamAsync(imageUrl);
//End Option 1)
//Option 2) - this will succeed
//var response = await httpclient.GetAsync(imageUrl);
//response.EnsureSuccessStatusCode();
//var stream = await response.Content.ReadAsStreamAsync();
//End Option 2)
return stream;
}
catch (Exception e)
{
Console.WriteLine($"Error downloading image");
throw;
}
}).ToList();
try
{
await Task.WhenAll(downloadTasks);
}
catch (Exception e)
{
Console.WriteLine("================ Failed to download one or more image " e.Message);
}
Console.WriteLine($"Successful downloads: {downloadTasks.Where(t => t.Status == TaskStatus.RanToCompletion).Count()}");
}
在 linqSelect陳述句的代碼塊中,Option 1)會如上所述失敗。如果您注釋掉 1),并取消注釋選項 2),那么一切都會成功。
任何人都可以解釋這里可能發生的事情嗎?
EDIT: This seems to work ok with .net core. I can reproduce this issue using .net framework 4.7.2 and below
EDIT2: I've also observed that if I increase the default connection limit by adding
ServicePointManager.DefaultConnectionLimit = 30;
then the error no longer happens, however this does not explain why it fails for Option 1) but succeeds for Option 2)
uj5u.com熱心網友回復:
正如所解釋的@RichardDeeming,HttpClient.GetStreamAsync通話HttpClient.GetAsync用HttpCompletionOption.ResponseHeadersRead。
代碼可以改寫如下:
async Task Main()
{
HttpClient httpclient = new HttpClient();
var imageUrl = "https://tenlives.com.au/wp-content/uploads/2020/09/Found-Kitten-0-8-Weeks-Busy-scaled.jpg";
var downloadTasks = Enumerable.Range(0, 15)
.Select(async u =>
{
try
{
//Option 1) - this will fail
var response = await httpclient.GetAsync(imageUrl, HttpCompletionOption.ResponseHeadersRead);
//End Option 1)
//Option 2) - this will succeed
//var response = await httpclient.GetAsync(imageUrl, HttpCompletionOption.ResponseContentRead);
//End Option 2)
response.EnsureSuccessStatusCode();
var stream = await response.Content.ReadAsStreamAsync();
return stream;
}
catch (Exception e)
{
Console.WriteLine($"Error downloading image");
throw;
}
}).ToList();
try
{
await Task.WhenAll(downloadTasks);
}
catch (Exception e)
{
Console.WriteLine("================ Failed to download one or more image " e.Message);
}
Console.WriteLine($"Successful downloads: {downloadTasks.Where(t => t.Status == TaskStatus.RanToCompletion).Count()}");
}
下一個HttpClient.GetAsync電話HttpClient.SendAsync。我們可以在GitHub 上看到該方法的代碼:
//I removed the uninterested code for the question
public Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationToken cancellationToken)
{
TaskCompletionSource<HttpResponseMessage> tcs = new TaskCompletionSource<HttpResponseMessage>();
client.SendAsync(request, cancellationToken).ContinueWith(task =>
{
HttpResponseMessage response = task.Result;
if(completionOption == HttpCompletionOption.ResponseHeadersRead)
{
tcs.TrySetResult(response);
}
else
{
response.Content.LoadIntoBufferAsync(int.MaxValue).ContinueWith(contentTask =>
{
tcs.TrySetResult(response);
});
}
});
return tcs.Task;
}
使用HttpClient.GetAsync(或SendAsync(HttpCompletionOption.ResponseContentRead)),讀取網路緩沖區中接收到的內容并將其集成到本地緩沖區中。
I'm not sure about the network buffer, but I think a buffer somewhere (network card, OS, HttpClient, ???) is full and blocks new responses.
You can correct the code by correctly managing this buffer, for example by disposing the associated streams :
var downloadTasks = Enumerable.Range(0, 15)
.Select(async u =>
{
try
{
var stream = await httpclient.GetStreamAsync(imageUrl);
stream.Dispose(); //Free buffer
return stream;
}
catch (Exception e)
{
Console.WriteLine($"Error downloading image");
throw;
}
}).ToList();
In .Net Core, the original code work without correction. The HttpClient class has been rewrited and certainly improved.
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/351419.html
標籤:.net httpclient
上一篇:一次對多個型別施加相同的型別約束
