(如果问题的某些部分被认为“过于基础”,我会道歉。我已经完成了有关异步等待的研究,但对我来说,这不是一个容易理解的概念。要么如此,要么我就没有找到了正确的资源。)我一直读到(或我所解释的)“使异步调用同步的方法是在其前面放置'await'”。因此,此语句产生的代码如以下简单代码所示:// CODE 1:public void async MyFunction(){ await SomeFunctionAsync();}也就是说:1)将await放在Async函数的前面,2)将async放在函数中,因为现在它包含一个await。但是根据我的经验,有时会表现得有些“滑稽”。我注意到的症状是有时它的行为就像是逃避我控制的线程。因此,第一个问题是:当您调用MyFunction()并且此函数包含async关键字时会发生什么?我的理解是(很容易混淆)不应将其称为MyFunctionAsync(),因为这是保留给返回Task的函数的。...所以我想出的另一种方法(似乎始终像同步类一样)是这种类型的代码:// CODE 2:public void MyFunction(){ var task = SomeFunctionAsync(); Task.WaitAll(task);}第二个问题:有人可以解释CODE 2的缺点(如果有)吗?另外,隐式的问题是,我有兴趣了解有关异步等待模式的任何误解。 最佳答案 我一直读到(或我所解释的)“使异步调用同步的方法是在其前面放置'await'”。一点也不。这是调用异步代码的串行方式,而不是同步的说法。 “同步”表示“阻塞当前线程”,await不会阻塞当前线程。但是,“ serial”的意思是“在下一件事之前执行此操作”,并且await会执行此操作。有关更多信息,请参见我的async intro。使用await是调用异步方法的最自然,最常见的方法。请注意,通常在向该方法添加async时,还应该将返回类型从void更改为Task。编译器将为此提供指导:如果仅将await放入而没有async,它将非常明确地为您建议下一个更改。  但是根据我的经验,有时会表现得有些“滑稽”。我注意到的症状是有时它的行为就像是逃避我控制的线程。这是因为您的代码使用的是async void而不是async Task。 async void是不自然的;您没有“控件”,因为您没有返回Task。更自然的方法是使方法async Task和await从调用者那里获得该任务,依此类推。这样,async很自然地在您的堆栈中“增长”-我们称之为“ async all the way”。  因此,第一个问题是:当您调用MyFunction()且此函数包含async关键字时会发生什么?我的理解是(令人困惑的是)不应将其称为MyFunctionAsync(),因为它保留给返回Task的函数。您对命名的理解是正确的。 MyFunction不是自然的(Task返回)异步方法。async void方法非常奇怪,行为不像普通的async方法。他们奇怪的行为是我推荐avoid async void的原因之一。但是既然你问...await方法中的async void就像常规await方法中的async一样(如我在async简介中所述):它将捕获当前上下文(当前SynchronizationContext或,并在异步操作完成后在该上下文中继续执行TaskScheduler方法,这就是为什么它像“控件外的线程”一样起作用-它仅在需要时恢复执行。您无法检测何时之所以完整,是因为该方法返回了async void而不是void。异常使事情变得更加奇怪。 Task方法在执行开始时捕获当前的async void,如果异常逃逸了SynchronizationContext方法,它将在捕获的async void上重新引发该异常。这通常会导致进程级崩溃。  第二个问题:有人可以解释CODE 2的弊端吗?它很容易导致我在博客中描述的deadlock situation。它还会将任务中的所有异常包装在SynchronizationContext中。最重要的是:不要阻塞异步代码。如果您仍然要阻止它,那为什么首先要使其异步呢?任何混合的阻塞和异步代码都应被视为具有较高优先级的技术债。没有在所有情况下都可行的解决方案,但是在将代码升级为适当的异步状态时,您可以临时使用各种hack。我在brownfield async development上的一篇文章中对它们进行了描述。关于c# - 使异步函数同步的后果,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/36383684/
10-17 01:45