I want to improve the performance of a program issuing multiple HTTP requests to the same external API endpoint. Therefore, I have created a console application to perform some tests. The method GetPostAsync
sends an asynchronous HTTP request to the external API and returns the result as a string.
private static async Task<string> GetPostAsync(int id)
{
var client = new HttpClient();
var response = await client.GetAsync($"https://jsonplaceholder.typicode.com/posts/{id}");
return await response.Content.ReadAsStringAsync();
}
Additionally, I have implemented the methods below to compare the execution time of multiple calls to await
and Task.WhenAll
.
private static async Task TaskWhenAll(IEnumerable<int> postIds)
{
var tasks = postIds.Select(GetPostAsync);
await Task.WhenAll(tasks);
}
private static async Task MultipleAwait(IEnumerable<int> postIds)
{
foreach (var postId in postIds)
{
await GetPostAsync(postId);
}
}
Using the integrated Stopwatch
class, I have measured the timings of the two methods and interestingly enough, the approach using Task.WhenAll
performed way better than its counterpart:
Issue 50 HTTP requests
- TaskWhenAll: ~650ms
- MultipleAwait: ~4500ms
Why is the method using Task.WhenAll
so much faster and are there any negative effects (i.e exception handling) when choosing this approach over the other?
WhenAll(Task[])Creates a task that will complete when all of the Task objects in an array have completed.
C# Language Async-Await Async/await will only improve performance if it allows the machine to do additional work.
Parallel. ForEach is multiple threads solution while Task. WhenAll will probably share threads. If tasks share the same thread, they are just pieces of the thread and will need more time to complete the tasks.
WhenAll() method in . NET Core. This will upload the first file, then the next file. There is no parallelism here, as the “async Task” does not automatically make something run in in parallel.
Why is the method using
Task.WhenAll
so much faster
It is faster because you are not awaiting GetPostAsync
. So actually every time you await client.GetAsync($"https://jsonplaceholder.typicode.com/posts/{id}");
the control will be returned to the caller which then can make another HTTP request. If you consider that HTTP request is much longer than creating the new client you effectively have the parallelism by running multiple HTTP requests in parallel. The WhenAll
will just create a suspension point and wait for all tasks to finish.
With the multiple await approach, you make HTTP requests sequentially one by one by await GetPostAsync(postId)
from foreach
loop. You start the task but at the same time, you make a suspension point and wait for it to finish.
are there any negative effects (i.e exception handling, etc.) when choosing this approach over the other?
There are no negative effects, using await/async
pattern handling exception become just, as usual, using try-catch
block. WhenAll
will aggregate all exception from each task which is in Faulted
state.
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