0

Imagine I have a list of classes that have the same async method, I can foreach on the list to do :

public async Task Test() { foreach (var runner in _runners) { await runner.Test(); } } 

but I can also do :

public void Test() { _runners.ForEach(async runner => await runner.Test()); } 

In this case, My test method isn't required to be async anymore. But will theses 2 methods have the same effect ?

3
  • Try to run the second method and see what happens. Hint: ForEach does not work well with async lambdas. Commented Jun 14, 2019 at 8:40
  • 1
    My test method isn't required to be async anymore - what is the problem with having test method to be async? Commented Jun 14, 2019 at 8:41
  • 1
    With the first method signature you have a guarantee that all async methods on your classes will be called (and completed) before leaving the method. In the second one I believe you have no such guarantee. Commented Jun 14, 2019 at 8:46

2 Answers 2

1

The differences are:


You can wait for a Task returned in first case and 'fire and forget' in second:

public async void TestCaller() { await Test(); // do things after all runners completed } 

When you are calling async void method you have to handle exceptions by yourself or they will be swallowed. You would rewrite second case like:

public void Test() { _runners.ForEach(async runner => { try { await runner.Test(); } catch (Exception e) { Console.Writeln(e.ToString()); } }); } 

That's looks not so pretty good.

Also each task in first case waits for the end of previous to start and in second case they are not (thanks Scott Chamberlain who corrected me in comments).

Sign up to request clarification or add additional context in comments.

5 Comments

Because of the async void the 2nd version also does not wait for the code started in the foreach to complete which is kind of important for a test.
Your edit is incorrect. if the code inside Test only returns tasks that are complete or have results then the tests will be all ran in sequence, not in parallel. He is a good article that goes in to some detail about it blogs.msdn.microsoft.com/benwilli/2015/09/10/…
I didn't get what case you talking about. Could you rephrase please?
If the code for runner.Test() was async Task Test() { Thread.Sleep(1000); await Task.Delay(0).ConfigureAwait(false); Thread.Sleep(1000); } and the foreach ran over two items it would take a total of 4000 ms to complete, if it was parallel it would take somewhere between 2000 to 3000 depending on the implmentation. read the linked article from my previous comment, it goes in a lot better detail.
Yes you are right they are executing on the same thread and 'parallel' is incorrect word for what they do.
1

Well, as I understand, equivalent of the code you wrote(async runner => await runner.Test()) would be

public static async void Do(Runner r) { await r.Test(); } 

And therefore you will not await the Do method(it is async void), while in the first version you actually execute next task only after the previous ended.

My test method isn't required to be async anymore

I think it looks like this just because there is no explicit async void anywhere, if you rewrite it with named methods it will be easier to see.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.