C#语言中的Async/await最佳实践

自从 C# 5 中引入 async/await 以来,开发人员之间一直对 async/await 关键字的最佳实践以及幕后实际发生的事情感到困惑。

让我们先从基础开始。

在 Windows 窗体的早期,UI 延迟与 I/O 操作所花费的时间成正比。这意味着,如果您尝试将数据保存到数据库中,并且数据库调用需要 20 秒,则用户只能等待这 20 秒。这是一个糟糕的用户体验(无论如何,在 2012 年之前谁关心用户体验)。

然后引入了 async/await。现在我们有了一种在两个线程之间划分工作的方法:

  1. UI 线程

  2. 工作线程

主代码在命中 await 关键字后立即由 UI 线程运行。在那一刻,UI线程可以自由地做其他事情,线程池中的另一个线程将接管做繁重的事情。

一旦我们从 DB 获得可用的数据,我们调用 UI 线程来执行 await 关键字之后的下一步指令。

这是用户可以与UI上的其他一些元素进行交互,直到数据被提取。

目前为止,一切都好?

现在让我们一一谈谈快速的最佳实践!

  1. **切勿使用 .Wait() 或 .结果:**它将锁定线程,您最终将使用更多线程来完成工作。始终使用 await,或者如果需要进行同步调用,请使用 .GetAwaiter() 中。GetResult()。

  2. 永远不要将 void 方法标记为异步 — 您需要查看异步方法引发的异常,对吗?如果你将 void 方法标记为异步,你的内部异常将被吞噬,并且(你知道)调试和找到这些异常会很痛苦。

  3. 始终等待您的异步 — 在没有 await 关键字的情况下使用异步方法没有任何好处。然后是一个同步调用。

  4. 如果代码有 9/10 次从不使用 await 关键字的热路径(如缓存)获取值,则使用 ValueTask 返回类型而不是 Task。

  5. 将 IAsyncEnumerable 用于流式处理数据。这意味着,如果存在集合数据巨大并且需要以块形式接收数据的情况,则使用 IAsyncEnumerable。

  6. ConfigureAwait — 好吧,我知道这对你来说是一场噩梦,但我会非常简单地解释这一点。如果未使用 ConfigureAwait(false) 方法标记 await 语句,它将调用相同的 UI 线程或工作线程(导致 await 语句的线程)以在 await 之后执行下一组指令。为什么这很糟糕?如果您的工作线程或 UI 线程正忙于执行其他操作,并且在等待后被调用执行下一组语句,该怎么办?

图片

默认情况下,ConfigureAwait(true) 值为 true。需要将其标记为 ConfigureAwait(false)。这将告诉编译器使用 threadpool 中的任何线程在 await 关键字之后执行语句,而不是特别调用 await 语句的线程。

4. 避免返回 await:如果中介类方法只是返回 await 方法,请不要用 async/await 标记它们。除了尝试/捕捉或使用

不良做法: 

图片

良好做法:

为什么?:它增加了使用 async/await 关键字的额外复杂性。在后台,编译器将异步方法转换为类。我们希望在中间类中做的就是一个返回任务的方法。调用的方法已经是“异步”和“等待”。我们不需要在每一步都这样做。

ConfigureAwait 仅在使用 SynchronizationContext 的框架中有用。ASP.Net Core 等 Web 应用框架没有 SynchronizationContext。因此,ConfigureAwait true/false 在 Web 应用程序中没有多大用处。

如果你喜欢我的文章,请给我一个赞!谢谢

  • 36
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值