首页 > 代码库 > Async/Await - Best Practices in Asynchronous Programming

Async/Await - Best Practices in Asynchronous Programming

https://msdn.microsoft.com/en-us/magazine/jj991977.aspx

 

Figure 1 Summary of Asynchronous Programming Guidelines

NameDescriptionExceptions
Avoid async voidPrefer async Task methods over async void methodsEvent handlers
Async all the wayDon’t mix blocking and async codeConsole main method
Configure contextUse ConfigureAwait(false) when you canMethods that require con­text

Avoid Async Void

You should prefer "async Task" to "async void". Async Task methods enable easier error-handling(propagate up or not), composability (Task.waitAll ...) and testability. The exception to this guideline is asynchronous event handlers, which must return void. This exception includes methods that are logically event handlers even if they’re not literally event handlers (for example, ICommand.Execute implementations).

 

Async All the Way

"Async all the way” means that you shouldn’t mix synchronous and asynchronous code without carefully considering the consequences. In particular, it’s usually a bad idea to block on async code by calling Task.Wait or Task.Result.  This is an common problem for programmers who try to convert just a small part of their application and wrapping it in a synchronous API so the rest of the application is isolated from the changes. Unfortunately, this can cause deadlocks, in the case of GUI or ASP.NET (not if in a console application). The exception semantic for await and Task.Wait is also different, Exception versus AggregateException. So do not do this except in the Main method for console applications.

 

Figure 5 The “Async Way” of Doing Things

 

To Do This …Instead of This …Use This
Retrieve the result of a background taskTask.Wait or Task.Resultawait
Wait for any task to completeTask.WaitAnyawait Task.WhenAny
Retrieve the results of multiple tasksTask.WaitAllawait Task.WhenAll
Wait a period of timeThread.Sleepawait Task.Delay

 

Configure Context

Await require context, see the following code, if you swap the commented-out lines in DelayAsync, it will not deadlock,

public static class DeadlockDemo{  private static async Task DelayAsync()  {    await Task.Delay(1000);
  //await Task.Delay(1000).ConfigureAwait(continueOnCapturedContext: false);
  }   // This method causes a deadlock when called in a GUI or ASP.NET context.
  public static void Test()  
  {     // Start the delay.    
    var delayTask = DelayAsync();     // Wait for the delay to complete.    
    delayTask.Wait();  
  }
}

 This technique is particularly useful if you need to gradually convert an application from synchronous to asynchronous.

You should not use ConfigureAwait when you have code after the await in the method that needs the context.

 

Async/Await - Best Practices in Asynchronous Programming