Async/Await 最佳做法

.NET Framework 4.5 中新增了对 async 和 await 支持,下面来看看如何正确的使用它们或者参考

避免 async void

async 方法有三种返回类型:Task、Task < T > 的 async 方法,任何返回 void 的方法都会成为返回 Task 的 async 方法。

    async Task 或 async Task < T >方法引发异常时,会捕获该异常并将其置于 Task 对象上。 对于 async void 方法,没有 Task 对象,因此 async void 方法引发的任何异常都会直接在 SynchronizationContext(在 async void 方法启动时处于活动状态)上引发。


     返回 Task 或 Task < T > 的 async 方法可以使用 await、Task.WhenAny、Task.WhenAll 等方便地组合而成。 返回 void 的 async 方法未提供一种简单方式,用于向调用代码通知它们已完成。  async void 方法会在启动和结束时通知 SynchronizationContext,但是对于常规应用程序代码而言,自定义 SynchronizationContext 是一种复杂的解决方案。

避免死锁

public static class DeadlockDemo
{
  private static async Task DelayAsync()
  {
    await Task.Delay(1000);
  }
  // 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();
  }
}
    每个 async 方法都具有自己的上下文,因此如果一个 async 方法调用另一个 async 方法,则其上下文是独立的。
    这种死锁的根本原因是 await 处理上下文的方式。 默认情况下,当等待未完成的 Task 时,会捕获当前“上下文”,在 Task 完成时使用该上下文恢复方法的执行。 此“上下文”是当前 SynchronizationContext(除非它是 null,这种情况下则为当前 TaskScheduler)。 GUI 和 ASP.NET 应用程序具有 SynchronizationContext,它每次仅允许一个代码区块运行。 当 await 完成时,它会尝试在捕获的上下文中执行 async 方法的剩余部分。 但是该上下文已含有一个线程,该线程在(同步)等待 async 方法完成。 它们相互等待对方,从而导致死锁。

    请注意,控制台应用程序不会形成这种死锁。 它们具有线程池 SynchronizationContext 而不是每次执行一个区块的 SynchronizationContext,因此当 await 完成时,它会在线程池线程上安排 async 方法的剩余部分。 该方法能够完成,并完成其返回任务,因此不存在死锁。 当程序员编写测试控制台程序,观察到部分异步代码按预期方式工作,然后将相同代码移动到 GUI 或 ASP.NET 应用程序中会发生死锁,此行为差异可能会令人困惑。
执行以下操作…替换以下方式…使用以下方式
检索后台任务的结果Task.Wait 或 Task.Resultawait
等待任何任务完成Task.WaitAnyawait Task.WhenAny
检索多个任务的结果Task.WaitAllawait Task.WhenAll
等待一段时间Thread.Sleepawait Task.Delay

配置上下文

随着异步 GUI 应用程序在不断增长,可能会发现 async 方法的许多小部件都在使用 GUI 线程作为其上下文。 这可能会形成迟滞,因为会由于“成千上万的剪纸”而降低响应性。

若要缓解此问题,请尽可能等待 ConfigureAwait 的结果

async Task MyMethodAsync()
{
  // Code here runs in the original context.
await Task.Delay(1000);
  // Code here runs in the original context.
await Task.Delay(1000).ConfigureAwait(
    continueOnCapturedContext: false);
  // Code here runs without the original
  // context (in this case, on the thread pool).
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值