ca9163d9
ca9163d9

Reputation: 29227

Consume the result of async calls (with different return type) as soon as any one of them is done?

The following code start T1Async(), T2Async(), T3Async(), T4Async() and wait for all of them to finish before consuming the results of these calls. However, the time to run these async calls can be short or very long randomly.

Task<int> T1Async() { };
Task<string> T2Async() { };
Task<ClassX> T3Async() { };
Task<ClassY> T4Async() { };

var t1 = T1Async();
var t2 = T2Async();
var t3 = T3Async();
var t4 = T4Async();

var v1 = await t1;
var v2 = await t2;
var v3 = await t3;
var v4 = await t4;
// Or Task.WhenAll(new Task[] { t1, t2, t3, t4 });

UseV1(v1); // Want these calls be run asap
UseV2(v2);
UseV3(v3);
UseV4(v4);

UseAll(v1, v2, v3, v4); // Need all the result here

How to consume the results as soon as the calling is done and make sure all the results are consumed?

Upvotes: 2

Views: 587

Answers (3)

ca9163d9
ca9163d9

Reputation: 29227

A testable case:

async Task<int> T1() { return await Task.FromResult(1); }
async Task<string> T2() { return await Task.FromResult("T2"); }
async Task<char> T3() { await Task.Delay(2000); return await Task.FromResult('A'); }
async Task<string> T4() { return await Task.FromResult("T4"); }

var t1 = T1().ContinueWith(x => { Console.WriteLine($"Use T1: {x.Result}"); return x.Result; });
var t2 = T2().ContinueWith(x => { Console.WriteLine($"Use T2: {x.Result}"); return x.Result; });
var t3 = T3().ContinueWith(x => { Console.WriteLine($"Use T3: {x.Result}"); return x.Result; });
var t4 = T4().ContinueWith(x => { Console.WriteLine($"Use T4: {x.Result}"); return x.Result; });
await Task.WhenAll(t1, t2, t3, t4);
Console.WriteLine("Done");

Upvotes: 0

huysentruitw
huysentruitw

Reputation: 28151

So you want to execute the UseVX tasks in parallel but await all the results (of different type) in order to pass it to the UseAll method.

Using Task.Run

var t1 = Task.Run(async () => { var x = await T1(); UseV1(x); return x; });
var t2 = Task.Run(async () => { var x = await T2(); UseV2(x); return x; });
var t3 = Task.Run(async () => { var x = await T3(); UseV3(x); return x; });
var t4 = Task.Run(async () => { var x = await T4(); UseV4(x); return x; });
await Task.WhenAll(t1, t2, t3, t4);
UseAll(t1.Result, t2.Result, t3.Result, t4.Result);

Using ContinueWith

var t1 = T1().ContinueWith(x => { UseV1(x.Result); return x.Result; });
var t2 = T2().ContinueWith(x => { UseV2(x.Result); return x.Result; });
var t3 = T3().ContinueWith(x => { UseV3(x.Result); return x.Result; });
var t4 = T4().ContinueWith(x => { UseV4(x.Result); return x.Result; });
await Task.WhenAll(t1, t2, t3, t4);
UseAll(t1.Result, t2.Result, t3.Result, t4.Result);

Upvotes: 3

Stephen Cleary
Stephen Cleary

Reputation: 457402

To run asynchronous code concurrently, use Task.WhenAll. To execute a method as each operation completes, introduce a new async method:

async Task<int> T1AndUseV1Async() { var v1 = await T1Async(); UseV1(v1); return v1; };
async Task<string> T2AndUseV2Async() { var v2 = await T2Async(); UseV2(v2); return v2; };
async Task<ClassX> T3AndUseV3Async() { var v3 = await T3Async(); UseV3(v3); return v3; };
async Task<ClassY> T4AndUseV4Async() { var v4 = await T4Async(); UseV4(v4); return v4; };

var t1 = T1AndUseV1Async();
var t2 = T2AndUseV2Async();
var t3 = T3AndUseV3Async();
var t4 = T4AndUseV4Async();

await Task.WhenAll(t1, t2, t3, t4);

UseAll(await t1, await t2, await t3, await t4);

Upvotes: 2

Related Questions