首页 > 解决方案 > 现在我们有了“await”关键字,使用 ContinueWith 方法有什么好处吗?

问题描述

图片如下代码:

var client = new HttpClient();
var response = await client.GetAsync("www.someaddress.yo");
string content = await response.Content.ReadAsStringAsync();

通过以下方式编写上述代码,除了可能节省单个线程之外,是否还有其他好处:

 var client = new HttpClient();
 string content = await client.GetAsync("www.someaddress.yo")
       .ContinueWith(r => r.Result.Content.ReadAsStringAsync()).Result;

如果我错了,请纠正我,但我相信在性能方面,两个代码最终都会做同样多的工作。

标签: c#

解决方案


第二个片段没有任何好处,在分配另一个任务对象时不会“保存”任何线程,并且通过将任何异常包装在 AggregateException 中来使调试和异常处理更加困难。

任务是对某事将在未来产生一些输出的承诺。那可能是:

  • 在线程池线程上运行的后台操作
  • 不在任何线程上运行的网络/IO 操作,而是等待网络/IO 驱动程序发出 IO 已完成的信号。
  • 一个计时器,它在间隔后发出任务信号。这里没有执行。
  • 一段时间后收到信号的 TaskCompletionSource。这里也没有执行

HttpClient.GetAsyncHttpClient.GetStringAsync或者Content.ReadAsStringAsync都是这样的IO操作。

await不会使任何东西异步运行。它只等待已经执行的任务完成而不阻塞。

ContinueWith使用第二个片段的方式没有任何收获。此代码只是分配另一个任务来包装由ReadAsStringAsync. .Result返回原始任务。

如果该方法失败,.Result将抛出一个AggregateException包含原始异常的异常 - 或者它是一个包含 AggregateException 的 AggregateException 包含原始异常?我不想知道。还不如用过Unwrap()。最后,一切还在等待。

唯一的区别是第一个片段在每次等待之后返回到原始同步上下文中。在桌面应用程序中,这将是 UI。在许多情况下,您希望这样做 - 这允许您使用响应更新 UI,而无需任何类型的编组。你可以写

var response = await client.GetAsync("www.someaddress.yo");
string content = await response.Content.ReadAsStringAsync();
textBox1.Text=content;

在其他情况下,您可能不希望这样,例如库编写者不希望库影响客户端应用程序。这就是ConfigureAwait(false)进来的地方:

var response = await client.GetAsync("www.someaddress.yo").ConfigureAwait(false);
string content = await response.Content.ReadAsStringAsync().ConfigureAwait(false);

推荐阅读