拍摄以下代码:
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;
如果我错了,请纠正我,但是我相信,从性能角度来看,两个代码最终都完成了相同的工作量。
答案 0 :(得分:3)
第二个片段没有任何好处,在分配另一个任务对象时不会“节省”任何线程,并且通过将所有异常包装在AggregateException中来使调试和异常处理变得更加困难。
任务是承诺,某些东西会在未来中产生一些输出。可能是这样的:
HttpClient.GetAsync
,HttpClient.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);