0

A couple years ago I was a little stuck on implementing async/await for the first time. I got an answer to my question [on this site], and I went on my merry way.

But lately, I got called out saying "that's not running those calls in parallel", even though it was VERY close to the exact solution that I received earlier.

Now I'm having second thoughts.

Here's the background, and the possible resolutions.

The whole point is that I don't want to execute method 1, wait for the results, then execute method 2 and wait for those results. That's too slow when the two method calls have nothing to do with each other.

I want to perform two method calls, both of which happen to be going to a database, but it could be anything, and I don't want processing to continue until I have the result of both calls.

public async Task<DataViewModel> GetDataInParallel()
{
    var asyncStuff = new
    {
        result1 = await _databaseRepo.QuerySomething(),
        result2 = await _databaseRepo.QuerySomethingElse()
    };

    return new DataViewModel(asyncStuff.result1, asyncStuff.result2);
}

vs

public async Task<DataViewModel> GetDataInParallel()
{
    var result1Task = _databaseRepo.QuerySomething();
    var result2Task = _databaseRepo.QuerySomethingElse();

    var asyncStuff = new
    {
        result1 = await result1Task,
        result2 = await result2Task
    };

    return new DataViewModel(asyncStuff.result1, asyncStuff.result2);
}

I use both versions in my website, but now I'm wondering if the ones that use option 1 are not doing things in parallel, and I'm seeing a performance degradation.

I'm not exactly sure on how to prove this out; does anyone know which is the correct version that will execute the two method calls in parallel? Or are they both right/wrong?

ganders
  • 7,285
  • 17
  • 66
  • 114
  • You're right... option1 does not do anything in "parallel." When you await something, the code below will not execute until the awaitable has completed. The second option is good. – John Wu Aug 21 '18 at 17:18
  • @JohnWu I"m not worried about the code below the await's. I only want the 2 function calls to execute (or start executing) at the same time. – ganders Aug 21 '18 at 17:20
  • With all due respect, I think you *are* worried about code below an await-- in your first example, the second database call is below an await, so it will not be started until the first one has finished. I think you want it to start before the first one is finished, as it will in your second example, where it is not below an await. – John Wu Aug 21 '18 at 17:21
  • @JohnWu thanks. So are you saying that option 2 DOES kick off both at the same time; since both method calls appear before any awaits? – ganders Aug 21 '18 at 17:22
  • @JohnWu can you post your comments as an answer as well so I can upvote you too? – ganders Aug 21 '18 at 17:26

1 Answers1

2

First version waits for first operation before starting second, so it is not parallel.

Second version does run them in parallel (starts both, then awaits both). You can make it more obvious by using Task.WhenAll:

public async Task<DataViewModel> GetDataInParallel()
{
    var result1Task = _databaseRepo.QuerySomething();
    var result2Task = _databaseRepo.QuerySomethingElse();

    await Task.WhenAll(result1Task, result2Task);

    return new DataViewModel(result1Task.Result, result2Task.Result);
}

See why WhenAll is a better choice: Why should I prefer single 'await Task.WhenAll' over multiple awaits?

Pavel Tupitsyn
  • 8,393
  • 3
  • 22
  • 44