-
Notifications
You must be signed in to change notification settings - Fork 5.2k
Description
I have conducted a basic performance test of HttpClient in .NET Core 2.0 versus HttpClient in .NET Framework 4.7 and have noticed a gap in performance. The .NET Framework 4.7 HttpClient/WebClient outperforms .NET Core's HttpClient by ~1.5-2x in terms of how long it takes to complete a batch of n requests.
Testing
The test is a console app (run in release mode on Windows 7 16GB 3.5GHz) with identical code for .NET Core/Framework that follows this sequence:
- Create a single, shared HttpClient instance with a maximum of n (for testing n=10,100) connections.
// .NET Core 2.0
var httpClient = new HttpClient(new HttpClientHandler { MaxConnectionsPerServer = 100 });
// .NET Framework 4.7
ServicePointManager.DefaultConnectionLimit = 100;
var httpClient = new HttpClient();
// .NET Framework 4.7 - WebClient instance is created ONCE PER REQUEST
ServicePointManager.DefaultConnectionLimit = 100;
var webClient = new WebClient();
- Start 10,000 simulataneous requests and time how long each request takes to complete + how long all take to complete. Here is code demonstrating how requests are made / timed.
private void RunTest(int count)
{
// requests is a list of Request data structures used to store individual request latency / responses
var requests = Enumerable.Range(0, count).Select(j => CreateRequest(j)).ToList();
// this stopwatch is for duration of all requests
var stopwatch = Stopwatch.StartNew();
// start all requests and wait for completion
var requestTasks = requests.Select(MakeRequest).ToArray();
Task.WaitAll(requestTasks);
stopwatch.Stop();
// total run time = stopwatch.ElapsedMilliseconds
}
private Task MakeRequest(Request request)
{
var stopwatch = Stopwatch.StartNew();
var response = await httpClient.GetStringAsync(request.Url);
stopwatch.Stop();
// save request duration and response
request.DurationMs = stopwatch.ElapsedMilliseconds;
request.ResponseId = ParseResponse(response);
}
I am testing against a basic python server that is well under capacity to rule out any server side bottlenecks. The server returns a simple JSON response containing an id field which is used to validate the HttpClient responses.
{ "id": "some_identifier" }
JSON deserialization / response validation is NOT included in performance stats.
Results
These are average statistics (in milliseconds) of 5 separate runs of 10,000 requests each. It is worth mentioning that the actual time spent on each request was much less with .NET Core's HttpClient, it's just that the batch of requests takes longer to complete as a whole vs .NET Framework.
| framework | total run time (ms) | avg req time (ms) | median req time (ms) | total time spent on requests (s) |
|---|---|---|---|---|
| .NET Core 2.0 | 5614 | 216 | 282 | 777 |
| .NET 4.7 | 3055 | 1355 | 1339 | 10,585 |