如果我等待我正在执行ReadAsStringAsync()的响应,我应该等待ReadAsStringAsync()吗?

如果我等待我正在执行ReadAsStringAsync()的响应,我应该等待 ReadAsStringAsync()吗? 为了进一步澄清,以下两者之间的区别或正确方法是什么? 它们实际上是一样的吗?

 var response = await httpClient.GetAsync("something"); var content = await response.Content.ReadAsStringAsync(); return new AvailableViewingTimesMapper().Map(content); 

要么

 var response = await httpClient.GetAsync("something"); var content = response.Content.ReadAsStringAsync(); return new AvailableViewingTimesMapper().Map(content.Result); 

你的第一个例子是正确的。 第二个示例在异步操作期间不会产生。 相反,通过获取content.Result属性的值,可以强制当前线程等待异步操作完成。

此外,正如评论者Scott Chamberlain指出的那样,通过阻止当前线程,您可能会引入死锁的可能性。 这取决于上下文,但await的常见场景是在UI线程中使用该语句,并且UI线程需要保持响应以满足各种需求,但包括能够实际处理等待操作的完成。

如果您避免使用第二个模式,即从您不知道的Task检索Result属性的值已经完成,您不仅可以确保有效使用线程,还可以确保不会遇到此常见的死锁陷阱。

ReadAsStringasync方法的原因是,实际读取数据的是IO操作。 即使您已经拥有http结果,内容也可能无法完全加载。 没有额外的线程或涉及大量的计算。

HttpClient.GetAsync允许您添加HttpCompletionOption以使GetAsync仅在加载整个HttpResult后才返回。 在这种情况下, HttpContent.ReadAsStringAsync将同步完成(所谓的快速路径),因为内容已经存在。

所以你一定要等待它。

另外:由于这可能是不依赖于UI线程返回的库代码,因此应该将.ConfigureAwait(false)添加到所有等待的方法调用中。

这是ReadAsStringAsync的 .NET源代码。 如果你深入研究LoadIntoBufferAsync ()方法,你会发现这将继续从HttpResponse读取缓冲区并导致潜在的进一步网络调用。 这意味着使用await而不是Result是一个好习惯。

 [__DynamicallyInvokable] public Task ReadAsStringAsync() { this.CheckDisposed(); TaskCompletionSource tcs = new TaskCompletionSource(); HttpUtilities.ContinueWithStandard(this.LoadIntoBufferAsync(), (Action) (task => { if (HttpUtilities.HandleFaultsAndCancelation(task, tcs)) return; if (this.bufferedContent.Length == 0L) { tcs.TrySetResult(string.Empty); } else { Encoding encoding1 = (Encoding) null; int index = -1; byte[] buffer = this.bufferedContent.GetBuffer(); int dataLength = (int) this.bufferedContent.Length; if (this.Headers.ContentType != null) { if (this.Headers.ContentType.CharSet != null) { try { encoding1 = Encoding.GetEncoding(this.Headers.ContentType.CharSet); } catch (ArgumentException ex) { tcs.TrySetException((Exception) new InvalidOperationException(SR.net_http_content_invalid_charset, (Exception) ex)); return; } } } if (encoding1 == null) { foreach (Encoding encoding2 in HttpContent.EncodingsWithBom) { byte[] preamble = encoding2.GetPreamble(); if (HttpContent.ByteArrayHasPrefix(buffer, dataLength, preamble)) { encoding1 = encoding2; index = preamble.Length; break; } } } Encoding encoding3 = encoding1 ?? HttpContent.DefaultStringEncoding; if (index == -1) { byte[] preamble = encoding3.GetPreamble(); index = !HttpContent.ByteArrayHasPrefix(buffer, dataLength, preamble) ? 0 : preamble.Length; } try { tcs.TrySetResult(encoding3.GetString(buffer, index, dataLength - index)); } catch (Exception ex) { tcs.TrySetException(ex); } } })); return tcs.Task; }