在体系结构C#

时间:2019-05-20 05:56:07

标签: c# asynchronous async-await

我已经苦苦挣扎了几天,要检查在哪里等待和不去哪里。

我有一个Repository类,该类从数据库中获取数据。 使用EntityFramework,代码将如下所示:

public async Task<List<Object>> GetAsync()
{
  return await context.Set<Object>().ToListAsync();
}

和消费者:

var data = await GetAsync();

并且在顶层,我也在等待此方法。 我应该只在其中一种方法上使用等待吗? 使用资源并在每次等待时创建新线程是否会降低性能?

  

我已经检查了评论中列出的问题,但它们不涉及性能问题,只是说您可以做到。我想要最佳实践以及为什么/不这样做的原因。

2 个答案:

答案 0 :(得分:1)

我想补充一点。 在某些async方法中,不需要使用async/await关键字。检测这种滥用很重要,因为添加async修饰符是有代价的。

E.G。您的示例中不需要async/await关键字。

public Task<List<Object>> GetAsync()
{
  return context.Set<Object>().ToListAsync();
}

然后:

var data = await GetAsync();

就好了。在这种情况下,您将返回Task<List<Object>>,然后在直接使用对象的地方等待。

我建议安装async await helper

答案 1 :(得分:0)

让我首先了解您问题的实质,困惑与在完整的呼叫链中在哪里使用异步以及在何处不使用以及如何评估使用对性能的影响有关,因为它可能会导致创建更多线程。如果提要超出了此范围,则在注释中添加详细信息,直到尝试回答它们为止。

让我们一一解决。

  

在调用链中的哪里使用异步,而在哪里不使用?

  • 在这里,当您使用实体框架访问数据库时,我可以安全地假设您正在使用基于IO的异步处理,这是跨语言和框架进行异步处理的最主要用例,而基于CPU的异步处理的用例是相对有限(也会对此进行解释)
  • 异步是一种可伸缩性功能,特别是用于IO处理而不是性能功能,通过异步处理简单来说,您可以确保托管服务器可以处理更多次用于IO处理的调用,因为调用不会阻塞并且它们只是处理通过网络处理请求,而处理线程又回到池中准备服务另一个请求,则在几毫秒内完成了处理的移交。
  • 处理完成后,如果纯线程不通过任何逻辑上的IO调用,则软件线程只需接收它们并将其传递回客户端,这又需要几毫秒,主要是在<1毫秒左右。
  

有什么好处

  • 想象一下,而不是对数据库进行IO同步调用,其中涉及的每个线程将仅等待结果到达,这可能会在几秒钟内完成,影响将是非常负面的,通常基于线程池的大小,您可以将服务器最多25-50个请求,它们也将对可处理的内核数进行答复,将在资源闲置并等待响应时不断浪费资源
  • 如果您进行同步调用,则无法在相同的设置中处理1000个以上的请求,我非常保守地认为,异步实际上会对可伸缩性产生巨大的影响,对于轻量级的调用,它可以通过单个托管进程轻松地满足数百万个请求< / li>
  

在后台之后,在完整链中使用异步的地方

  • 无处不在,从开始到结束,从入口点到实际出口点的IO调用都是可行的,因为这是释放池线程的实际调用,因为它通过网络调度调用
  • 尽管要记住await在给定的位置不允许进一步的代码处理相同的方法,即使它减轻了线程的负担,所以最好是如果存在多个独立调用,它们使用Task.WhenAll进行汇总,并且代表任务正在等待,当所有任务完成成功/错误(无论状态如何)时,它都会返回
  • 如果通过使用Task.WaitTask.Result之类的方法在异步之间进行了中断,则它将不会保持纯异步调用,并且会阻塞调用线程池线程。
  

如何进一步增强异步功能?

  • 在Pure库调用中,异步是由线程池启动的,而分派线程可以与接收线程不同,并且调用不需要重新输入相同的上下文,您应使用ConfigureAwait(false),这意味着它不会等待重新输入原始上下文,可以提高性能
  • await一样,在整个链条中使用ConfigureAwait(false),直到结尾。这仅对在线程池上进行大量答复的库有效
  

是否创建了线程

  

变化

  • 基于CPU的异步处理,您需要在后台进行处理,因为当前线程需要响应,主要是在像WPF这样的Ui情况下
  

用例

  • 所有系统,特别是非MS框架,例如node js,都将异步处理作为基本原理,并且将接收端的数据库服务器集群调整为接收和处理数百万个呼叫
  • B2C呼叫,它期望每个请求都是轻量且有效载荷有限

编辑1:

在这种特定情况下,hereToListAsync在默认情况下都是异步的,因此您可以跳过这种情况,如variopus注释中所列,尽管您可以回顾一下Stepehen Cleay的文章,可能不是一个很好的策略,因为收益很小,而且使用不当的负面影响很大。