awaitReadAsStringAsync()
の場合awaited実行している応答がReadAsStringAsync()
の場合さらに明確にするために、以下の違いや正しい方法は何ですか?それらは事実上同じですか?
var response = await httpClient.GetAsync("something");
var content = await response.Content.ReadAsStringAsync();
return new AvailableViewingTimesMapper().Map(content);
OR
var response = await httpClient.GetAsync("something");
var content = response.Content.ReadAsStringAsync();
return new AvailableViewingTimesMapper().Map(content.Result);
最初の例は正しいものです。 2番目の例は、非同期操作中に生成されません。代わりに、content.Result
プロパティの値を取得することにより、非同期操作が完了するまで現在のスレッドを強制的に待機させます。
さらに、コメンターのScott Chamberlainが指摘しているように、現在のスレッドをブロックすることにより、デッドロックの可能性を導入することができます。それはコンテキストに依存しますが、await
の一般的なシナリオはUIスレッドでそのステートメントを使用することであり、UIスレッドはさまざまなニーズに対して応答性を維持する必要がありますが、実際に待機中の操作の完了。
2番目のパターン、つまり、完了していないResult
からTask
プロパティの値を取得することを避けた場合、スレッドの効率的な使用を確保できるだけでなく、この一般的なデッドロックトラップに対して確実に対処してください。
ReadAsString
がasync
メソッドである理由は、実際にデータを読み取ることがIO操作であるためです。すでにhttpの結果がある場合でも、コンテンツが完全にロードされない場合があります。スレッドまたは大きな負荷のコンピューティングが含まれます。
_HttpClient.GetAsync
_ を使用すると、HttpCompletionOption
を追加して、GetAsync
全体を読み込んだ後にのみHttpResult
を返すことができます。その場合、_HttpContent.ReadAsStringAsync
_はコンテンツが既に存在するため、同期的に完了します(いわゆるfastpath)。
だからあなたは間違いなくそれを待つべきです。
また、これはおそらくUIスレッドに戻ることに依存しないライブラリコードであるため、.ConfigureAwait(false)
をすべての待機メソッド呼び出しに追加する必要があります。
ReadAsStringAsyncの.NETソースコードを次に示します。 LoadIntoBufferAsync()メソッドをさらに深く見ると、これによりHttpResponseからのバッファーの読み取りが継続され、ネットワーク呼び出しがさらに発生する可能性があります。つまり、Resultの代わりにawaitを使用することをお勧めします。
[__DynamicallyInvokable]
public Task<string> ReadAsStringAsync()
{
this.CheckDisposed();
TaskCompletionSource<string> tcs = new TaskCompletionSource<string>();
HttpUtilities.ContinueWithStandard(this.LoadIntoBufferAsync(), (Action<Task>) (task =>
{
if (HttpUtilities.HandleFaultsAndCancelation<string>(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;
}