1

I have an executor method:

public static async Task<T> ExecuteAsync(Func<Task<T>> method)
{
    await method();
}

When calling it both

await ExecuteAsync( () => obj.MethodAsync());

and

await ExecuteAsync( async () => await obj.MethodAsync());

seem to work just fine and finish in roughly the same amount of time while spawning roughly the same amount of threads. It was my understanding that in the first case the method will be executed synchronously inside the lambda and the lambda would be executed asynchronously, and in the second example both the method and the lambda would be executed asynchronously.

abigicic
  • 25
  • 5
  • 2
    Possible dupe: https://stackoverflow.com/questions/38017016/async-task-then-await-task-vs-task-then-return-task – gunr2171 Mar 30 '20 at 14:34
  • 1
    Possible duplicate: [Any difference between “await Task.Run(); return;” and “return Task.Run()”?](https://stackoverflow.com/questions/21033150/any-difference-between-await-task-run-return-and-return-task-run) TL;DR there is hardly any difference. – Theodor Zoulias Mar 30 '20 at 14:52
  • Does this answer your question? [Any difference between "await Task.Run(); return;" and "return Task.Run()"?](https://stackoverflow.com/questions/21033150/any-difference-between-await-task-run-return-and-return-task-run) – JSteward Mar 30 '20 at 22:52
  • Relevant: [Eliding async and await](http://blog.stephencleary.com/2016/12/eliding-async-await.html). – Stephen Cleary Mar 31 '20 at 01:34
  • Thanks for the references to other questions. I think that the answer I've selected does a good job of reasoning and explaining what's happening in the case when I make the lambda async. – abigicic Mar 31 '20 at 08:23

1 Answers1

2

async and await apply only to method definitions.

async means that the compiler will generate a state machine for the method.

await means that the compiler will generate code to synchronously wait for the invoke method to complete.

ExecuteAsync(() => obj.MethodAsync())

translates something to:

[CompilerGenerated]
private sealed class <>c__DisplayClass0_0
{
    public C<T> obj;

    internal Task<T> <M>b__0()
    {
        return obj.MethodAsync();
    }
}

// ...

<>c__DisplayClass0_0 <>c__DisplayClass0_ = new <>c__DisplayClass0_0();
<>c__DisplayClass0_.obj = obj;
ExecuteAsync(new Func<Task<T>>(<>c__DisplayClass0_.<M>b__0));

On the other hand,

ExecuteAsync( async () => await obj.MethodAsync())

translates to something more complex involving nested state machines.

Try sharplab.io to see the lowered code.

In fact, the simplest version would be:

await ExecuteAsync(obj.MethodAsync);
Paulo Morgado
  • 14,111
  • 3
  • 31
  • 59