web-dev-qa-db-ja.com

ReadAsStringAsync()を実行している応答を待っている場合、ReadAsStringAsync()を待つ必要がありますか?

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);
22
Toby Holland

最初の例は正しいものです。 2番目の例は、非同期操作中に生成されません。代わりに、content.Resultプロパティの値を取得することにより、非同期操作が完了するまで現在のスレッドを強制的に待機させます。

さらに、コメンターのScott Chamberlainが指摘しているように、現在のスレッドをブロックすることにより、デッドロックの可能性を導入することができます。それはコンテキストに依存しますが、awaitの一般的なシナリオはUIスレッドでそのステートメントを使用することであり、UIスレッドはさまざまなニーズに対して応答性を維持する必要がありますが、実際に待機中の操作の完了。

2番目のパターン、つまり、完了していないResultからTaskプロパティの値を取得することを避けた場合、スレッドの効率的な使用を確保できるだけでなく、この一般的なデッドロックトラップに対して確実に対処してください。

21
Peter Duniho

ReadAsStringasyncメソッドである理由は、実際にデータを読み取ることがIO操作であるためです。すでにhttpの結果がある場合でも、コンテンツが完全にロードされない場合があります。スレッドまたは大きな負荷のコンピューティングが含まれます。

_HttpClient.GetAsync_ を使用すると、HttpCompletionOptionを追加して、GetAsync全体を読み込んだ後にのみHttpResultを返すことができます。その場合、_HttpContent.ReadAsStringAsync_はコンテンツが既に存在するため、同期的に完了します(いわゆるfastpath)。

だからあなたは間違いなくそれを待つべきです。

また、これはおそらくUIスレッドに戻ることに依存しないライブラリコードであるため、.ConfigureAwait(false)をすべての待機メソッド呼び出しに追加する必要があります。

9
Kai Brummund

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;
    }
6
Teoman shipahi