我看到使用和不使用呼叫者的sections
之间存在巨大的性能差异。我觉得唯一的区别应该在于回报。即,如果我使用class_id
,则调用者方法应在返回下一条语句之前等待被调用方法的响应,否则调用者方法无需等待响应,并且可以继续执行其他语句。
在我的情况下,在调用方方法中使用和不使用await
会有很大的性能差异。即,如果我不使用await
,它将继续在调用方中执行下一条语句而无需等待,但比在调用方中使用await
快得多。
此外,我是否使用async并正确等待?
代码
await
答案 0 :(得分:0)
不,我想说的是您对什么是异步/等待以及何时使用它们尚不了解。您应该阅读await / async和Task,以充分了解其实现,最重要的是使用此结构的原因。关于异步代码的常见误解是它使代码更快。这通常是不准确的。实际上,它会使特定代码变慢一些,但 却使代码更具响应性,并允许您轻松利用服务器的处理能力。
从最简单的意义上讲,您编写或调用的代码通常必须等待某些事情。这可能用于I / O,例如磁盘访问,数据库或其他通信。它还可能需要等待计算和代码完成需要花费大量时间才能完成的工作。如果您有多个任务,每个任务平均需要5秒钟,然后同步启动它们,则第一个任务将在5秒钟后完成,第二个任务在10秒钟后完成,第三个任务在15秒钟后完成。
例如:
var result1 = DoSomething1(); //5 seconds.
var result2 = DoSomething2(); //5 seconds.
var result3 = DoSomething3(); //5 seconds.
var total = result1 + result2 + result3; // executes after 15 seconds.
现在,如果我执行DoSomething()async
并返回Task<int>
var result1 = DoSomething1();
var result2 = DoSomething2();
var result3 = DoSomething3();
int total = result1 + result2 + result3; // ERROR! result1,2,3 are Taxk<int> representing they are a handle to executing code.
相反,如果我们不在乎结果,而只是做一个Console.WriteLine("Done");
,您几乎会立即达到总成绩,因为您有效完成的工作是启动3个任务。现在,每个任务将花费超过5秒的时间来运行并返回其结果。为了论证,假设5.1秒。 (它将小于此值,而更像是0.01)。此成本损失用于上下文切换。您的代码“似乎”可以立即运行,因为当工作线程仍在执行任务时,我们已到达“完成”。 (我们不在乎结果吗?处理任何异常吗?)
所以,现在我们有3种异步方法可以并行运行,我们可以使用await获得结果:
var result1 =等待DoSomething1(); var result2 =等待DoSomething2(); var result3 =等待DoSomething3(); int total =结果1 +结果2 +结果3; //现在可以使用。
但是,您认为执行此操作需要多长时间?答案将是15.3秒。通过使用Await,每个操作都必须等待另一个操作完成。
“那么,这到底意味着什么?!”我确定有人问过。好吧,要使它们并行运行,可以这样编写:
var result1 = DoSomething1(); var result2 = DoSomething2(); var result3 = DoSomething3(); int total =等待结果1 +等待结果2 +等待结果3; //这也可以。
现在执行时间? 5.1秒。
“ AHA!速度更快!”是的,总的来说,但这只是因为这样可以,在安全地为每个操作利用不同的线程以及任何代码的结果之前,等待之前不依赖于先前的异步语句和处理的任何内容线程安全的引用。还有其他注意事项,例如同步上下文,异常处理等。还要记住,像EF的DbContext这样的对象不是 线程安全的,因此,调用每个引用相同DbContext而不等待它们的顺序等待的方法(因为它应该并行更快)会导致很少的麻烦问题和错误。
这仅涵盖异步/等待的最基本知识。您应该从Microsoft和其他来源研究更多有关其用途和局限性的信息,最重要的是何时使用。它不是灵丹妙药,也不应该默认设置为可用,因为在大多数情况下,我已经看过它使用它,这会导致性能问题以及涉及非线程安全代码的并发错误。它旨在用于可能需要一段时间才能运行的操作,并且您可以在等待结果之前安全地完成一些代码或启动并行,独立的操作。如果您的同步代码存在性能问题,那么99.5%的时间这些问题不会可以由async / await解决。在考虑并行操作之前,最好先用现有的代码穷尽所有可能的解释。异步/等待的主要参数是使代码更具响应性。
一些开始的材料:
https://www.codingame.com/playgrounds/4240/your-ultimate-async-await-tutorial-in-c/introduction https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/async/
我确定针对SO问题/解答和其他资源还会提出其他建议。
最后一点:不要这样做:
catch (Exception ex)
{
throw new Exception(ex.ToString());
}
引发新异常将生成新的调用堆栈。如果您没有采取任何措施来处理异常,则只需删除try / catch块。如果您正在做某事,并且希望随后出现异常,请使用throw
:
catch (Exception ex)
{
VibrantTransaction.Rollback();
AuditTransaction.Rollback();
throw;
}
这将保留现有的异常调用堆栈。