Async_Await 一些概念性的东西
在伯乐在线看到的一篇关于async_await的文章,总结得挺好 1.0 “async”这个关键字让我们能够在方法内部使用“await”关键字,我们并没有在线程池的线程中运行这个方法,只是激活了await关键字(并管理方法结果)。 2.0 异步方法在开始执行时,和其它任何方法都是一样的。也就是说,在遇到“await”关键字(或者抛出异常)之前,方法都是同步运行的。 3.0 “await”关键字可以让事情异步运行。await会检查可等待操作是否已经结束,如果可等待操作已经完成,方法就会继续运行。 如果“await”发现可等待操作还没有完成,那么就会异步地执行。它会告诉可执行操作,在完成之后,继续执行方法剩余的部分,然后从异步方法返回。 过些时候,当可执行操作完成后,它会执行异步方法的剩余部分。如果你在等待一个内置的可等待操作(例如Task),那么异步方法的剩余部分会在“await”返回之前的“上下文”中执行。 我喜欢将“await”当做“异步等待”。也就是说,异步方法会暂停,直到可等待操作结束(因此它在等待),但是这种异步等待导致调用方在获取结果之前都可以不等待await之后的代码执行! 4.0 上面提到的上下文是什么呢? 简单的回答是: 如果你是在UI线程上,那么它就是UI上下文。 如果你是在响应一个ASP.NET的请求,那么它就是ASP.NET的请求上下文。 否则,通常它是一个线程池上下文。 复杂的回答: 如果 SynchronizationContext.Current 不为空,那么它是当前的 SynchronizationContext(UI上下文和ASP.NET请求上下文都是 SynchronizationContext 上下文)。否则,它是当前的 TaskScheduler(TaskScheduler.Default是线程池上下文)。 比如: private async void DownloadFileButton_Click(object sender, EventArgs e) { // 既然我们使用异步的方式等待,那么UI线程就不会被文件下载所阻塞。 await DownloadFileAsync(fileNameTextBox.Text); // 既然我们从UI上下文中恢复,我们就可以直接访问UI元素。而无需调用Invoke为控件赋值 resultTextBox.Text = "File downloaded!"; } 5.0 避免上下文 通过调用 ConfigureAwait 方法并传入false的方式,来告诉“等待者”不要捕捉当前的上下文。 private async Task DownloadFileAsync(string fileName) { // 使用HttpClient或者其他任何方式来下载文件内容 var fileContents = await DownloadFileContentsAsync(fileName).ConfigureAwait(false); // 请注意由于ConfigureAwait(false),我们并没有在原来的上下文中。 // 相反,我们运行在线程池上。 // 将文件内容写入到外部的磁盘文件中。 await WriteToDiskAsync(fileName, fileContents).ConfigureAwait(false); // 这里第二次调用ConfigureAwait(false)并不是*必需*的,但这是一个最佳实践。 } 6.0 参考文章 https://blogs.msdn.microsoft.com/pfxteam/2012/04/12/asyncawait-faq/ https://blogs.msdn.microsoft.com/pfxteam/2011/01/13/await-anything/