C# 整个链中的等待是否会影响asp.net性能?

C# 整个链中的等待是否会影响asp.net性能?,c#,asp.net,asp.net-core,C#,Asp.net,Asp.net Core,假设我有以下类似异步方法的调用堆栈: async Task<T> Method1() { return await Method2(); } async Task<T> Method2() { return await Method3(); } async Task<T> Method3() { return await httpClient.ReadAsync(...); } 异步任务方法1() { 返回等待方法2(); } 异步任务

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

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

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

async Task<T> Method3()
{
   return await httpClient.ReadAsync(...);
}
异步任务方法1()
{
返回等待方法2();
}
异步任务方法2()
{
返回等待方法3();
}
异步任务方法3()
{
返回wait wait httpClient.ReadAsync(…);
}
因为只有Method3有真正的异步IO请求。我可以在方法1中等待一次吗?下面的方法会稍微提高性能吗

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

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

Task<T> Method3()
{
   return httpClient.ReadAsync(...);
}
异步任务方法1()
{
var task=Method2();
返回等待任务;
}
任务方法2()
{
返回方法3();
}
任务方法3()
{
返回httpClient.ReadAsync(…);
}
是的,确实如此,但是(假设您的示例),因为这是非常糟糕的代码

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

它们应该是这样的:

任务方法1(){return Method2;}

您可以在Method2之前执行其他非异步操作

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

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

如果你被打断了,看看那些谈论基于性能的任务。对不起,录像,没有记录。然后看哪一个讨论了异步中性能的最佳实践。

是的,是的,但是(假设您的示例),因为这是非常糟糕的代码

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

它们应该是这样的:

任务方法1(){return Method2;}

您可以在Method2之前执行其他非异步操作

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

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


如果你被打断了,看看那些谈论基于性能的任务。对不起,录像,没有记录。然后看看哪一个是关于异步性能的最佳实践。

是吗?在这里尝试并不是最好的解决方案。这是谷歌的一个案例——dotnet开发者在博客中广泛讨论了这一点,包括针对C#8的优化支持ValueTask,以使其更快。尝试它不会给你带来那些讨论。Watch@TomTom:这是不相关的,返回ValueTask和在每个层中等待是不同的事情,在上面的示例中,ValueTask没有任何变化,仍然需要分配一个任务(
httpClient.ReadAsync(…)
将始终返回一个任务,并且基本上总是异步的,从不同步).ValueTask仅在可以完成时为您保存分配的
任务
synchronously@TomTom你是什么意思?试一试不是最好的解决办法?这是什么建议?对代码进行基准测试以查看其运行速度和分配的内存量,并对其进行测试以验证其返回的结果是否正确,这正是我们应该做的。基准测试尤其困难,尤其是对于这样的微代码。此外,基准测试也会忽略另一种方法可能更好的事实——一种你在基准测试中没有看到的方法。是吗?尝试一下并不是最好的解决方案。这是谷歌的一个案例——dotnet开发者在博客中广泛讨论了这一点,包括针对C#8的优化支持ValueTask,以使其更快。尝试它不会给你带来那些讨论。Watch@TomTom:这是不相关的,返回ValueTask和在每个层中等待是不同的事情,在上面的示例中,ValueTask没有任何变化,仍然需要分配一个任务(
httpClient.ReadAsync(…)
将始终返回一个任务,并且基本上总是异步的,从不同步).ValueTask仅在可以完成时为您保存分配的
任务
synchronously@TomTom你是什么意思?试一试不是最好的解决办法?这是什么建议?对代码进行基准测试以查看其运行速度和分配的内存量,并对其进行测试以验证其返回的结果是否正确,这正是我们应该做的。基准测试尤其困难,尤其是对于这样的微代码。此外,基准测试也会忽略另一种方法可能更好的事实——你在基准测试中看不到的方法。好吧,
非常糟糕的代码
说得有点过火,至少在我看来,从性能角度看,
ValueTask
是一个更好的选择1。在大多数实际情况下,使用普通的旧任务并不是那么糟糕。这一问题主要是关于的影响,而这一问题与
ValueTask
Task
都同样相关,因为这显然是错误的。如上所述,ValueTask没有带来额外的好处。在这种情况下,其a)避免创建异步状态机(并且开销很小)(async/await使编译器生成一个状态机来处理异步调用,但看起来仍然像“sync”代码)b)更改异常行为。等待代码将检查等待的任务,并在等待时抛出异常,因此可以使用try/catch捕获它。在
return SomeMethod()
代码中,您无法捕获异常。在那里,它们将被抛出等待状态,这意味着在等待
方法1
的代码中更高的位置。这可能是需要的,也可能不是需要的,这取决于用例:A
try{returnmethod3();}catch(Exceptio