无法理解异步并等待

我一直在尝试理解as#/ await和C#中的任务,但是尽管观看了YouTubevideo,阅读文档和遵循复数课程,但仍然失败了。

我希望有人能够帮助回答这些略微抽象的问题,以帮助我的大脑。

1.为什么他们说async / await在它自己的async关键字什么都不做而且await关键字添加一个暂停点时启用’asynchonrous’方法? 没有添加一个暂停点,强制该方法同步动作,即在继续之前完成await标记的任务。

2.显然除了事件处理程序之外你不应该使用async void,那么你如何正常调用异步方法呢? 似乎为了使用await关键字调用异步方法,调用它本身的方法/类需要标记为async。 我见过的所有例子都“启动”了一个带有事件处理程序的异步void方法。 你将如何“逃避”async / await的包装以运行该方法?

3。

public async Task SaveScreenshot(string filename, IWebDriver driver) { var screenshot = driver.TakeScreenshot(); await Task.Run(() => { Thread.Sleep(2000); screenshot.SaveAsFile(filename, ScreenshotImageFormat.Bmp); Console.WriteLine("Screenshot saved"); }); Console.WriteLine("End of method"); } 

回到1.这看起来像一个同步方法。 当它到达Task.Run时执行暂停,因此Console.WriteLine("End of method"); 在任务完成之前不会执行。 也许整个方法本身将在代码中触发它时异步执行? 但回到2,你需要等待调用它,否则你得到消息’因为没有等待这个调用..’因此添加await将导致该执行点同步等等。

任何帮助理解这一点将非常感激。

没有添加一个暂停点,强制该方法同步动作,即在继续之前完成await标记的任务。

不,你想到的这个词是“顺序的”,而不是“同步的”。 await导致异步顺序代码。 “顺序”意思是“一次一个”; “同步”意思是“阻塞直到完成”。

你如何正常调用异步方法?

使用await

你将如何“逃避”async / await的包装以运行该方法?

理想情况下,你没有 。 你一直都是异步的 。 现代框架(包括ASP.NET MVC,Azure Functions / WebJobs,NUnit / xUnit / MSTest等)都允许您拥有返回Task入口点。 不太现代的框架(包括WinForms,WPF,Xamarin Forms,ASP.NET WebForms等)都允许async void入口点。

因此,理想情况下,您不会从同步代码中调用异步代码。 如果你考虑一下异步代码什么,这是有道理的:它的全部意义在于阻塞调用线程,所以如果你在异步代码上阻塞调用线程,那么你首先会失去异步代码的所有好处。

也就是说,在极少数情况下您需要同步处理代码。 例如,如果您正处于转换为异步的过程中,或者您受到强制您的代码同步且无法使用async void的库/框架的约束。 在这种情况下,你可以使用我的文章中的一个hack褐色异步 。

你的理解非常好:)。 您似乎缺少的主要观点是.NET中的“异步”方法意味着可以在不阻塞调用线程的情况下停止执行的方法。

正如您在(1)中指出的那样, async关键字基本上允许使用await并且要求返回类型为voidTask/Taskawait只是指示当前方法暂停执行,直到任务完成。

你在这里缺少的是它只挂起当前的方法 。 它不会阻止方法执行的线程。 这在像WPF应用程序的UI线程这样的情况下很重要。 挂起方法执行,一切都继续运行,阻塞线程,应用程序停止响应。

您通常希望async调用一直到顶部(如事件处理程序),这允许最大的灵活性并防止死锁情况。 然而; 您可以等待Task返回方法完成Wait

 someAsyncMethod.Wait() 

或者获得返回值:

  var result = someAsyncMethod.Result; 

请注意,这两个都是同步的并阻止调用线程。 如果异步任务正在等待调用线程上的其他一些工作完成,这样做可能会导致死锁。

以上应该在(3)中回答你的问题; 方法本身似乎是同步执行的(这是await/async的神奇之处)但是该任务不会阻塞调用线程。

它是异步的,因为您不必等待方法返回。 在您的代码中,您可以调用异步方法并将任务保存在变量中。 继续做其他事情。 之后,当需要方法结果时,等待响应(任务)。

 // Synchronous method. static void Main(string[] args) { // Call async methods, but don't await them until needed. Task task1 = DoAsync(); Task task2 = DoAsync(); Task task3 = DoAsync(); // Do other stuff. // Now, it is time to await the async methods to finish. Task.WaitAll(task1, task2, task3); // Do something with the results. Console.WriteLine(task1.Result); Console.ReadKey(); } private static async Task DoAsync() { Console.WriteLine("Started"); await Task.Delay(3000); Console.WriteLine("Finished"); return "Success"; } // Output: // Started // Started // Started // Finished // Finished // Finished // Success