我正在学习异步/等待,在阅读本文之后,不要阻塞异步代码
这是异步/等待适合于 IO 和 CPU 绑定的方法
我注意到@Stephen Cleary文章中的一个提示。
使用ConfigureAwait(false)避免死锁是一种危险的做法。您必须对阻塞代码调用的所有方法(包括所有第三方和第二方代码)的传递闭包中的每个等待使用ConfigureAwait(false)。使用ConfigureAwait(false)避免死锁充其量只是一种黑客行为)。
它再次出现在我上面所附的帖子代码中。
public async Task<HtmlDocument> LoadPage(Uri address)
{
using (var httpResponse = await new HttpClient().GetAsync(address)
.ConfigureAwait(continueOnCapturedContext: false)) //IO-bound
using (var responseContent = httpResponse.Content)
using (var contentStream = await responseContent.ReadAsStreamAsync()
.ConfigureAwait(continueOnCapturedContext: false)) //IO-bound
return LoadHtmlDocument(contentStream); //CPU-bound
}
据我所知,当我们使用配置等待(false)时,其余的异步方法将在线程池中运行。为什么我们需要将它添加到传递闭包中的每个等待中?我自己只是认为这是我所知道的正确版本。
public async Task<HtmlDocument> LoadPage(Uri address)
{
using (var httpResponse = await new HttpClient().GetAsync(address)
.ConfigureAwait(continueOnCapturedContext: false)) //IO-bound
using (var responseContent = httpResponse.Content)
using (var contentStream = await responseContent.ReadAsStreamAsync()) //IO-bound
return LoadHtmlDocument(contentStream); //CPU-bound
}
这意味着在使用块时第二次使用配置等待(false)是无用的。请告诉我正确的方法。提前谢谢。
据我所知,当我们使用 ConfigureAwait(false)
时,异步方法的其余部分将在线程池中运行。
很接近,但有一个重要的警告,你错过了。当您使用<code>ConfigureAwait(false)</code>等待任务后恢复时,您将在任意线程上恢复。注意“恢复时”这几个字
让我给你看点东西:
public async Task<string> GetValueAsync()
{
return "Cached Value";
}
public async Task Example1()
{
await this.GetValueAsync().ConfigureAwait(false);
}
考虑示例1
中的等待
。尽管您正在等待异步
方法,但该方法实际上并不执行任何异步工作。如果<code>异步
跟你预想的不太一样,对吧?然而,这并不罕见。许多< code>async方法可能包含不需要调用方挂起的快速路径。缓存资源的可用性就是一个很好的例子(谢谢,@jakub-dąbek!),但是还有很多其他原因导致< code>async方法可能提前退出。我们经常在方法的开始检查各种条件,看看我们是否可以避免做不必要的工作,< code>async方法也不例外。
让我们看另一个示例,这次来自WPF应用程序:
async Task DoSomethingBenignAsync()
{
await Task.Yield();
}
Task DoSomethingUnexpectedAsync()
{
var tcs = new TaskCompletionSource<string>();
Dispatcher.BeginInvoke(Action(() => tcs.SetResult("Done!")));
return tcs.Task;
}
async Task Example2()
{
await DoSomethingBenignAsync().ConfigureAwait(false);
await DoSomethingUnexpectedAsync();
}
看一看示例2
。我们<code>等待<code>的第一个方法总是异步运行。当我们点击第二个<code>等待<code>时,我们知道我们正在线程池线程上运行,所以第二次调用时不需要<code>配置等待(false)Async并返回任务
,但我们的第二个方法不是使用异步
和等待
编写的。相反,它执行自己的调度,并使用TaskCompletionSource
传递结果。当您从<code>等待<code>恢复时,您可能会<sup>[1]
这里关键的一点是,你通常不知道一个“可行的”方法到底是做什么的。不管有没有< code > configurewait ,您都可能会运行到某个意想不到的地方。这可能发生在< code>async调用堆栈的任何级别,因此避免无意中获得单线程上下文所有权的最可靠方法是对每个< code>await使用< code > configurewait(false),即贯穿传递闭包。
当然,有些时候你可能想在当前的背景下继续工作,这没关系。这就是为什么它是默认行为的表面原因。但是如果你真的不需要它,那么我推荐默认使用< code > configurewait(false)。对于库代码来说尤其如此。库代码可以从任何地方被调用,所以最好坚持最小惊奇的原则。这意味着当您不需要时,不要将其他线程锁定在调用者的上下文之外。即使您在库代码中处处使用< code > configurewait(false),调用者仍然可以选择在他们的原始上下文上继续,如果这是他们想要的。
[1]此行为可能因框架和编译器版本而异。
在模块声明中,requires和requires可传递模块语句之间有什么区别 例如:
问题内容: 我有一个将对象保存到数据库的EJB。在我看到的一个示例中,一旦保存了此数据(EntityManager.persist),就会调用EntityManager.flush();。为什么我需要这样做?我要保存的对象未附加,以后在该方法中也不会使用。实际上,一旦保存,该方法就会返回,并且我希望资源会被释放。(示例代码也在remove调用上执行此操作。) 问题答案: 调用将强制数据立即被持久保
问题内容: 大多数情况下,我看到的finally块仅用于 我的问题是,如果f的范围以封闭块结尾,为什么我们需要在finally中将其关闭? 问题答案: 因为垃圾回收与资源清理 不是 一回事。 例如,如果您有一个超出范围的JDBC连接对象,则没有信号发送到数据库服务器以指示不再需要打开的游标和连接。没有这些消息,您最终将耗尽可用的游标和连接数。 与文件句柄和任何其他资源相同。自己清理后。
我在互联网上找到了例子,但这并没有给我充分的理解。使用WebFlux时的标准CRUD。 路由器: 处理程序: 我是对的还是这个说法错了?
我正在阅读有关java中的同步概念的信息,并遇到了同步语句。 我想知道,为什么我们向它传递参数,尽管它看起来像静态块(这只是一个例子),并且传递的参数没有指定任何数据类型。 例: 如果有人知道,请解释。
问题内容: 我开始使用RxJS,但我不明白为什么在此示例中我们需要使用类似or 的函数;数组的数组在哪里? 如果有人可以直观地解释正在发生的事情,那将非常有帮助。 问题答案: 当您有一个Observable的结果是更多Observable时,可以使用flatMap。 如果您有一个由另一个可观察对象产生的可观察对象,则您不能直接过滤,缩小或映射它,因为您有一个可观察对象而不是数据。如果您生成一个可观