Подтвердить что ты не робот

Должен ли я ждать 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);
4b9b3361

Ответ 1

Ваш первый пример правильный. Второй пример не возникает во время асинхронной операции. Вместо этого, получив значение свойства content.Result, вы вынудите текущий поток дождаться завершения асинхронной операции.

Кроме того, как отмечает комментатор Скотт Чемберлен, блокируя текущий поток, можно ввести возможность тупика. Это зависит от контекста, но общий сценарий для await заключается в том, чтобы использовать этот оператор в потоке пользовательского интерфейса, а поток пользовательского интерфейса должен оставаться отзывчивым для множества потребностей, но в том числе иметь возможность фактически обрабатывать завершение ожидаемая операция.

Если вы избежите второго шаблона, т.е. извлечение значения свойства Result из Task, которое вы не знаете, завершилось, вы не только сможете обеспечить эффективное использование ваших потоков, но также можете обеспечить общая тупиковая блокировка.

Ответ 2

Причина, по которой метод ReadAsString является методом асинхронной проверки, заключается в том, что фактически чтение данных является операцией ввода-вывода. Содержимое может быть просто не полностью загружено, даже если у вас уже есть результат http. Нет дополнительных потоков или больших нагрузок, связанных с использованием.

HttpClient.GetAsync позволяет добавить HttpCompletionOption, чтобы GetAsync возвращался только после загрузки всего HttpResult. В этом случае HttpContent.ReadAsStringAsync завершит синхронно (так называемый fastpath), потому что контент уже существует.

Итак, вы должны обязательно его ждать.

Также: поскольку это, вероятно, код библиотеки, который не зависит от возврата в потоке пользовательского интерфейса, вы должны добавить .ConfigureAwait(false) ко всем ожидаемым вызовам методов.

Ответ 3

Вот исходный код .NET для ReadAsStringAsync. Если вы посмотрите глубже в метод LoadIntoBufferAsync(), вы увидите, что это будет поддерживать буфер чтения из HttpResponse и приведет к потенциальному дальнейшему сетевому вызову. Это означает, что рекомендуется использовать ожидание вместо результата.

[__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;
    }