2

I'm looking for best practice around calling multiple async methods where each next method relies on the values returned from one before.

I'm experimenting with 2 approaches

1) https://dotnetfiddle.net/waPL9L

public async void Main()
    {       
        var T1 = await Sum(2,5);
        var T2 = await Sum(T1, 7);
        var T3 = await Sum(T2, 7);      

        Console.WriteLine(T3);
    }

    public async Task<int> Sum(int num1, int num2){
        return await Task.Run(() => {
            // for some reason if i use Sleep... I don't see any results at all...
            //Thread.Sleep(2000);
            return num1 + num2;
        });
    }

2) https://dotnetfiddle.net/1xycWH

public async void Main()
    {
        var T1 = Sum(2,5);
        var T2 = Sum(T1.Result, 7);
        var T3 = Sum(T2.Result, 7);

        //var myVar = T3.Result;

        var listOfTasks = new List<Task>{T1,T2,T3};

        await Task.WhenAll(listOfTasks);

        Console.Write(T3.Result);
    }

    public async Task<int> Sum(int num1, int num2){
        return await Task.Run(() => {
            Thread.Sleep(1000);
            return num1 + num2;
        });
    }

Just trying to understand best approach as I'm kind of new to async programming.

Thanks in Advance!

Johny

Johny
  • 387
  • 1
  • 7
  • 20
  • 2
    None... **Firstly** you are using `StartNew` which you should probably be using the new `Task.Run`. **Secondly**, you are wrapping task in an `async` method, do not use `Task.Run` in the implementation of the method; instead, use `Task.Run` to call the method, **Thirdly** none of your methods are suffixed with *Async*, **Lastly** you are calling `Result` on an `async` method and will like deadlock in some situations, you should never really need to do this.. – TheGeneral Feb 21 '19 at 02:51
  • trying to understand why you are using async when what you want is sequential execution – Jonathan Niu Feb 21 '19 at 03:04
  • Points taken. In reality, my 3 async methods do some Db operations in 2 different databases, and each next method relies on value from one before... I did some more research after posting this question and I understand now how calling Result on an async method can cause deadlock... http://blog.stephencleary.com/2012/07/dont-block-on-async-code.html Any suggestion on how should I go about this? @MichaelRandall Appreciate your time! – Johny Feb 21 '19 at 03:04
  • @JonathanNiu Thanks for your time. please see my comment above ^ – Johny Feb 21 '19 at 03:05
  • To answer the question, using `await` and awaiting the result is probably the most straight forward and easy to understand in any normal situation – TheGeneral Feb 21 '19 at 03:06
  • @JonathanNiu In my actual code... I have 2 class libraries (each interacts with different database) - methods that are exposed via the repositories are async... one of the business requirements lead to this convoluted situation where i've to interact with multiple dbs to get what I want... – Johny Feb 21 '19 at 03:07
  • So its ok for me to await each call by simply using await keyword? @MichaelRandall. That's how i currently have it and it works... wasn't sure if thats the best/efficient way. – Johny Feb 21 '19 at 03:12
  • 3
    It is the most readable and succinct, IMO, it is the best way – TheGeneral Feb 21 '19 at 03:13
  • @MichaelRandall Thank you! Really appreciate your time and help, I definitely feel more educated! – Johny Feb 21 '19 at 03:45

1 Answers1

9

I'm looking for best practice around calling multiple async methods where each next method relies on the values returned from one before.

A lot of asynchronous questions can be answered by looking at the synchronous equivalent. If all the methods are synchronous and each method depends on the results of previous methods, how would that look?

var T1 = Sum(2,5);
var T2 = Sum(T1, 7);
var T3 = Sum(T2, 7);

Then the asynchronous equivalent would be:

var T1 = await SumAsync(2,5);
var T2 = await SumAsync(T1, 7);
var T3 = await SumAsync(T2, 7);

P.S. For future reference, do not insert StartNew or Task.Run as generic placeholders for asynchronous code; they just confuse the issue since they have very specific use cases. Use await Task.Delay instead; it's the Thread.Sleep of the async world.

Stephen Cleary
  • 437,863
  • 77
  • 675
  • 810
  • 1
    I'm actually reading your article "Don't block on Async Code" and its kinda funny to get your response over here at the same time haha. Thank you so much for the explanation - Had no clue that Task.Delay can be awaited. Also, I feel much better after these comments here confirming that approach 1 is the way to go. Will mark this as answer. – Johny Feb 21 '19 at 03:43