Performance Boost from Reusing HttpClient Connections

By FoxLearn 1/21/2025 9:50:18 AM   21
When you reuse an HttpClient instance for multiple requests, the connection is kept open and reused for each subsequent request.

Reusing connections can boost performance in the following scenarios:

  • Sending multiple sequential requests to the same endpoint.
  • Sending concurrent requests to the same endpoint.

To demonstrate the performance improvement, I'll send multiple requests to a URL.

The first request will require opening a new connection, while the following requests will reuse the established connection. I’ll measure the response times for both cases.

It's important to discard the first measurement (due to warm-up time), but for this scenario, I’ll perform a warm-up request to a different URL (localhost) before beginning the actual performance test.

Below is a C# code sample that measures the time taken to open and reuse a connection using HttpClient:

public static async Task MeasureConnectionReuse()
{
    var apiUrl = "https://jsonplaceholder.typicode.com/todos/1";
    var httpClient = new HttpClient();

    // Warm up the framework with a request to localhost
    await SendRequest(httpClient, "https://localhost:9000/api/warmup");

    Stopwatch stopwatch = Stopwatch.StartNew();
    await SendRequest(httpClient, apiUrl);
    stopwatch.Stop();
    Console.WriteLine($"Time to open a new connection: {stopwatch.ElapsedMilliseconds}ms");

    List<double> responseTimes = new List<double>();

    // Measure response times for reusing the connection
    for (int i = 0; i < 100; i++)
    {
        stopwatch.Restart();
        var response = await SendRequest(httpClient, apiUrl);
        stopwatch.Stop();
        responseTimes.Add(stopwatch.ElapsedMilliseconds);
    }

    Console.WriteLine($"Reused connection response times: Min={responseTimes.Min()}ms Max={responseTimes.Max()}ms Avg={responseTimes.Average()}ms");
}

public static async Task<string> SendRequest(HttpClient httpClient, string url)
{
    var response = await httpClient.GetAsync(url);
    response.EnsureSuccessStatusCode();
    return await response.Content.ReadAsStringAsync();
}

When running the example above, the first request opens a new connection, and the subsequent requests reuse the existing connection. This is verified by observing the reduced time for reuse requests.

For example, the results might look like this:

  • Cost of opening a new connection: 524ms
  • Cost of reusing the connection: Min=50ms Max=60ms Avg=55ms

In this case, the request that had to open a new connection took 524ms, while the reused connections took 55ms on average, making reuse around 9.5 times faster than opening a new connection.

Reusing connections is highly effective, providing performance boosts between 5x to 9.5x in most scenarios.