I am trying to use HttpClient synchronously but when I make many concurrent requests it stops working. I wrote two tests, one for asynchronous usage and one for synchronous usage. TestMethod
always returns response after 4 seconds. Asynchronous test works fine. Almost all requests are timed out in synchronous test, only ~20 last requests are successful. I tried both using a single HttpClient
for requests and creating new HttpClient
instance for each new requests. No difference. Maybe it has something to do with this deadlock.
I am using VS2013 with .NET Framework 4.5.1 targeting Framework 4.5. I get HttpClient via NuGet: <package id="Microsoft.Net.Http" version="2.2.15" targetFramework="net45" />
I don't want to use HttpClient
asynchronously just yet because it means that I have to rewrite my whole app. Any ideas what am I doing wrong here?
// all 800 requests complete successfully
[Test]
public async void Asyncmethod()
{
var sw = new Stopwatch();
sw.Start();
var client = new HttpClient();
client.Timeout = TimeSpan.FromSeconds(15);
var tasks = Enumerable.Range(0, 800).Select(x => Task.Run(async () =>
{
try
{
var swx = new Stopwatch();
swx.Start();
var response = await client.GetStringAsync("http://localhost:7002/TestMethod").ConfigureAwait(false);
swx.Stop();
Console.WriteLine(x + " " + response + " in " + swx.ElapsedMilliseconds + " ms.");
}
catch (Exception e)
{
Console.WriteLine(x + " Exception: " + e.Message);
}
})).ToArray();
await Task.WhenAll(tasks);
sw.Stop();
Console.WriteLine(sw.ElapsedMilliseconds);
}
// almost all of 800 requests time out
[Test]
public void Syncmethod()
{
var sw = new Stopwatch();
sw.Start();
var client = new HttpClient();
var tasks = Enumerable.Range(0, 800).Select(x => Task.Run(() =>
{
try
{
var swx = new Stopwatch();
swx.Start();
var response = client.GetStringAsync("http://localhost:7002/TestMethod");
if (response.Wait(15000))
{
swx.Stop();
Console.WriteLine(x + " " + response.Result + " in " + swx.ElapsedMilliseconds + " ms.");
}
else
{
swx.Stop();
Console.WriteLine(x + " timed out.");
}
}
catch (Exception e)
{
Console.WriteLine(x + " Exception: " + e.Message);
}
})).ToArray();
foreach (var task in tasks)
task.Wait(60000);
sw.Stop();
Console.WriteLine(sw.ElapsedMilliseconds);
}
I do recommend that you use await
for HttpClient
instead of Wait
. If you truly want synchronous requests, consider using WebClient
which supports synchronous methods.
That said, I believe the reason you're seeing that behavior is due to ServicePointManager.DefaultConnectionLimit
, which will throttle the number of requests to a given server. If you want to have large numbers of concurrent requests to the same server (synchronous or asynchronous), then you'll need to increase that limit (it is 2 by default for UI applications).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With