How do you start multiple HttpClient.GetAsync()
requests at once, and handle them each as soon as their respective responses come back? First what I tried is:
var response1 = await client.GetAsync("http://example.com/");
var response2 = await client.GetAsync("http://stackoverflow.com/");
HandleExample(response1);
HandleStackoverflow(response2);
But of course it's still sequential. So then I tried starting them both at once:
var task1 = client.GetAsync("http://example.com/");
var task2 = client.GetAsync("http://stackoverflow.com/");
HandleExample(await task1);
HandleStackoverflow(await task2);
Now the tasks are started at the same time, which is good, but of course the code still has to wait for one after the other.
What I want is to be able to handle the "example.com" response as soon as it comes in, and the "stackoverflow.com" response as soon as it comes in.
I could put the two tasks in an array an use Task.WaitAny()
in a loop, checking which one finished and call the appropriate handler, but then ... how is that better than just regular old callbacks? Or is this not really an intended use case for async/await? If not, how would I use HttpClient.GetAsync()
with callbacks?
To clarify -- the behaviour I'm after is something like this pseudo-code:
client.GetAsyncWithCallback("http://example.com/", HandleExample);
client.GetAsyncWithCallback("http://stackoverflow.com/", HandleStackoverflow);
Declare an async function and pass your callback in:
And then just call it multiple times:
You can use a method that will re-order them as they complete. This is a nice trick described by Jon Skeet and Stephen Toub, and also supported by my AsyncEx library.
All three implementations are very similar. Taking my own implementation:
You can then use it as such:
Another approach is to use TPL Dataflow; as each task completes, post its operation to an
ActionBlock<T>
, something like this:Either of the above answers will work fine. If the rest of your code uses / could use TPL Dataflow, then you may prefer that solution.
You can use
ContinueWith
andWhenAll
to await one newTask
, task1 and task2 will be executed in parallel