someone
someone

Reputation: 575

concat result of three tasks in an async method in a proper way

I am very new in async programming. I was wonder if there is any way for these tasks to run simultaneously. Consider I have this code:

public async Task<IList<WebData>> GetAllAsync()
{
    var twitterData = await ProvidetwitterDataAsync();
    var facebookData = await ProvidefacebookDataAsync();
    var linkedinData = await ProvidelinkedinDataAsync();
    return twitterData .Concat(facebookData ).Concat(linkedinData ).ToList();
}

I think because I used await twitterData that Task should be done and after that next Task will be started, because I wanted to concat results of these three lists I wrote it in this way, I wanted to know is there any way that these three tasks can be done simultaneously? Is this way of implementation correct or is there a better way?

Upvotes: 6

Views: 3522

Answers (2)

ProgrammingLlama
ProgrammingLlama

Reputation: 38767

Something like this should work.

public async Task<IList<WebData>> GetAllAsync()
{
    var twitter = ProvidetwitterDataAsync();
    var facebook = ProvidefacebookDataAsync();
    var linkedin = ProvidelinkedinDataAsync();
    return (await Task.WhenAll(twitter, facebook, linkedin)).SelectMany(d => d).ToList();
}

The 3 tasks can run concurrently, and then you wait for all of them, combine their results into a single list and return it.

Upvotes: 6

Eric Lippert
Eric Lippert

Reputation: 660148

am very new in async programming.

Then let's be careful and describe what is actually happening carefully.

I was wonder if there is any way to these tasks run simultaneously.

Don't think of tasks as running simultaneously, since that implies a concurrency model that might or might not be true. All you know about a task is that it will complete asynchronously.

Think about it like this: if you have some tasks like "pay my bills" and "mow my lawn", and "eat lunch" you might pay half your bills, then start mowing the lawn, then pause halfway through mowing the lawn, eat some lunch, pay a few more bills, and then finish mowing the lawn. You did the three tasks asynchronously but never did them concurrently. You were never mowing the lawn at the same time as eating your lunch. Sometimes asynchronous tasks really are running at the same time as other tasks, but not always, so don't think of tasks as running concurrently always.

I think because I used await twitterData should be done and after that next task will be started,

Correct. The key insight is await pauses an asynchronous workflow until the task is completed. Await does NOT make a call asynchronous. The task returned by the call is already an asynchronous workflow. An await simply means "if this task is not complete then find something else to do and come back here when it is complete".

So: how do you write your workflow so that you are not serializing the tasks? You put the awaits after the tasks are started. The right way to write your code is:

public async Task<IList<WebData>> GetAllAsync()
{
  var twitter = ProvideTwitterDataAsync();
  var facebook = ProvideFacebookDataAsync();
  var linkedin = ProvideLinkedinDataAsync();
  var twitterData = await twitter;
  var facebookData = await facebook;
  var linkedinData = await linkedin;
  return twitterData .Concat(facebookData ).Concat(linkedinData ).ToList();
}

Now the three tasks are started asynchronously, and then we pause the workflow until all three are completed, and then we concatenate the results.

Upvotes: 8

Related Questions