【问题标题】:Does await in the whole chain impact the asp.net performance? [duplicate]整个链中的 await 会影响 asp.net 的性能吗? [复制]
【发布时间】:2020-02-24 19:06:37
【问题描述】:

假设我有以下类似异步方法的调用堆栈:

async Task<T> Method1()
{
   return await Method2();
}

async Task<T> Method2()
{
   return await Method3();
}

async Task<T> Method3()
{
   return await httpClient.ReadAsync(...);
}

因为只有 Method3 有真正的异步 IO 请求。我可以在 Method1 中等待一次吗?下面的方法会稍微提高性能吗?

async Task<T> Method1()
{
   var task = Method2();
   return await task;
}

Task<T> Method2()
{
   return Method3();
}

Task<T> Method3()
{
   return httpClient.ReadAsync(...);
}

【问题讨论】:

  • try it out了吗?
  • 在这里尝试不是最好的解决方案。这是 google 的一个案例 - dotnet 开发人员在博客中对此进行了广泛讨论,包括 C#8 支持 ValueTask 的优化,以使其更快。尝试一下不会给你那些讨论。观看channel9.msdn.com/Shows/On-NET/…
  • @TomTom:这无关,返回 ValueTask 并在每一层等待是另一回事,在上面的示例中 ValueTask 没有任何改变,仍然需要分配一个任务(httpClient.ReadAsync(...) 将始终返回一个任务,它基本上总是异步的,从不同步)。ValueTask 仅在可以同步完成时为您节省Task 的分配
  • @TomTom 你是什么意思尝试它不会是最好的解决方案?这是什么建议?对代码进行基准测试以查看它的运行速度和分配的内存量,并对其进行测试以验证它返回正确的结果正是应该做的。
  • 基准测试特别困难,尤其是对于像这样的微代码。同样对其进行基准测试也会忽略另一种方法可能更好的事实 - 您在基准测试中看不到的方法。

标签: c# asp.net asp.net-core


【解决方案1】:

是的,确实如此,但是(假设您的示例)因为它是非常糟糕的代码。

方法 1 和方法 2 不应该是异步的

它们应该是这样的:

任务 Method1 (){ return Method2; }

你可以在 Method2 之前做其他非异步的东西。

像你一样将它们链接起来意味着创建了许多额外的任务,这会产生影响——语言现在也接受 ValueTask 的原因之一。如果您在调用子方法之前在方法中执行操作,然后您所做的只是等待,则没有理由等待 - 您可以返回内部任务,从而跳过完整创建的对象。

在文档中重复使用类似的任务,包括为经常发生的结果预先生成返回任务。

如果您感兴趣,请查看https://channel9.msdn.com/Shows/On-NET/Understanding-how-to-use-Task-and-ValueTask - 那些谈论基于性能的任务。抱歉,有视频,没有文字记录。然后观看 https://channel9.msdn.com/Events/Build/BUILD2011/TOOL-829T 讨论异步性能的最佳实践。

【讨论】:

  • 好吧,REALLY bad code 说得有点过分了,至少在我看来,因为从性能的角度来看,ValueTask 是一个更好的选择 1. 使用普通的旧 Task 不是那样在大多数实际情况下都不好 2. 这个问题主要是关于eliding async-await 的影响,这个问题与ValueTaskTask 同样相关
  • 必须对此投反对票,因为它完全错误。正如上面的 cmets 所解释的,ValueTask 没有带来额外的好处。在这种情况下,它 a)避免创建异步状态机(async/await 使编译器生成状态机来处理异步调用但仍然看起来像“同步”代码)的创建(和很少的开销)b)它改变了异常行为.等待代码将检查等待的任务并在您等待的地方抛出异常,因此您可以使用 try/catch 捕获它。在return SomeMethod() 代码中,你无法捕捉到异常,他们将在等待中抛出
  • 这意味着在等待Method1 的代码中更进一步。这可能需要也可能不需要,具体取决于用例:try { return Method3(); } catch (Exception ex) { ... } 永远不会捕获异常,链接的问题也正确解释了这一点
猜你喜欢
  • 1970-01-01
  • 2014-04-08
  • 1970-01-01
  • 2012-08-15
  • 2021-09-10
  • 2015-08-10
  • 1970-01-01
  • 1970-01-01
  • 2012-09-29
相关资源
最近更新 更多