107

In order to get some solid base understanding about asynchronous programming and the await, I would like to know what the difference is between these two code snippets when it comes to multi threading and the execution sequence and time:

This:

public Task CloseApp()
{
        return Task.Run(
                         ()=>{ 
                                // save database
                                // turn off some lights
                                // shutdown application
                          });
}

Versus this:

public async Task CloseApp()
{
        await Task.Run(
                         ()=>{ 
                                // save database
                                // turn off some lights
                                // shutdown application
                          });
}

if I am calling it in this routine:

private async void closeButtonTask()
{
    // Some Task 1
    // ..

    await CloseApp();
    
    // Some Task 2
    // ..
}
Mark Rotteveel
  • 100,966
  • 191
  • 140
  • 197
Khalil Khalaf
  • 9,259
  • 11
  • 62
  • 104
  • 3
    They have subtle differences in how exceptions are wrapped – SLaks Jun 24 '16 at 15:32
  • Possible dupe http://stackoverflow.com/questions/21033150/any-difference-between-await-task-run-return-and-return-task-run – DavidG Jun 24 '16 at 15:39
  • 1
    closeButtonTask should rather return Task instead of void. – michal.jakubeczy Jul 13 '18 at 07:57
  • 1
    This [sharplab sample](https://sharplab.io/#v2:EYLgZgpghgLgrgJwgZwLQFEAeAHJzkCWA9gHYBqUCBUwANigD4ACADAARMCMA3ALABQrDpwCsffgKYBmDgCY2AYTYBvAW3UcZTABwcAbGwCCyAJ4kAxoYDuUAjAAUASjYBeAHwcAnEdMWFUWnoIJ3ENNjUNaX0fM3MAJQh4BBInVw9jWP9AiGDHUI0I9VwCADdYCGiMvwCg1Pd9ADoFIgBbbHoYCAATJj1xAF8gA) I put together shows the underlying machinery. – Drew Noakes Oct 29 '18 at 12:56

2 Answers2

93

It is almost the same (in terms of threads etc.). But for the second one (using await) a lot more overhead will be created by the compiler.

Methods declared as async and using await are converted into a state machine by the compiler. So when you hit the await, the control flow is returned to the calling method and execution of your async method is resumed after the await when the awaited Task has finished.

As there is no more code after your await, there is no need to use await anyway. Simply return the Task is enough.

René Vogt
  • 43,056
  • 14
  • 77
  • 99
  • 3
    *"when you hit the await, the control flow is returned to the calling method"* -- The control flow **might** be returned to the calling method, particularly it won't return when the awaited task is already complete. – acelent Jun 24 '16 at 15:43
  • @acelent thx for the detail, never thought about what happens when the task is already finished. I don't know the exact details of what the compiler does line by line. – René Vogt Jun 24 '16 at 15:45
  • 1
    I totally dont understand this – monstro Mar 29 '18 at 16:01
  • 1
    When your task will be finished a thread from Thread Pool will call the `Post` method and notify the caller that the task was finished. As I remember the rest of async method will be executed as `ContinueWith`. Execution will continue from await point, but it can be executed in different thread. – Joseph Katzman Oct 17 '18 at 10:41
  • This blog post explains it very cleanly. https://devblogs.microsoft.com/premier-developer/dissecting-the-async-methods-in-c/ In short, there is some optimization logic to prevent unnecessary waiting. – Daniel Dror Sep 15 '19 at 07:45
14

There are very few differences between the two approaches. Basically, they share the same semantics. However, the version with async/await wraps the execution of the inner task in an outer compiler-generated task. The non-async version does not. Thus, the non-async version is (very marginally) more efficient.

Falanwe
  • 4,636
  • 22
  • 37
  • *"the non-async version is (very marginally) more efficient."* -- That depends, if the method is called very often, then the async/await version might generate noticeable garbage: the state machine and another task. – acelent Jun 24 '16 at 15:45
  • @acelent: generating some generation 0 garbage still feels pretty marginal to me – Falanwe Jun 24 '16 at 16:14
  • 3
    Ok, I just want to point out that is not always the case for everyone ([1](https://msdn.microsoft.com/en-us/magazine/hh456402.aspx)), and you can't rely on tasks or references to tasks to be that ephemeral ([2](https://channel9.msdn.com/Events/Build/BUILD2011/TOOL-829T), [at 0:25:40](https://channel9.msdn.com/Events/Build/BUILD2011/TOOL-829T#time=25m40s), [at 0:30:20](https://channel9.msdn.com/Events/Build/BUILD2011/TOOL-829T#time=30m20s)). – acelent Jun 27 '16 at 17:39