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

Что происходит при ожидании результата задачи?

Я использую HttpClient для отправки данных на удаленную службу в проекте .NET 4.0. Я не беспокоюсь об этой блокировке операции, поэтому я решил, что могу пропустить ContinueWith или async/await и использовать Result.

Во время отладки я столкнулся с проблемой, когда удаленный сервер не реагировал. Когда я прошел через код, мне показалось, что мой код просто перестает работать в третьей строке... текущая строка указателя стека перестает выделяться желтым цветом и не переходит к следующей строке. Он просто исчез. Мне потребовалось некоторое время, чтобы понять, что я должен дождаться запроса на тайм-аут.

var client = new HttpClient();
var task = client.PostAsync("http://someservice/", someContent);
var response = task.Result;

Мое понимание заключалось в том, что вызов результата в Задаче заставил код выполнять синхронно, чтобы вести себя как это (я знаю, что в HttpClient нет метода Post):

var client = new HttpClient();
var response = client.Post("http://someservice/", someContent);

Я не уверен, что это плохо, я просто пытаюсь обойти это. Это правда, что в силу того факта, что HttpClient возвращает результаты непосредственно вместо результатов, мое приложение автоматически использует асинхронность, даже когда я думаю, что избегаю этого?

4b9b3361

Ответ 1

В Windows все операции ввода/вывода являются асинхронными. Синхронные API - это просто абстракция.

Итак, когда вы используете HttpWebRequest.GetResponse, на самом деле происходит запуск I/O (асинхронно), а вызывающий поток (синхронно) блокирует его до завершения.

Аналогично, когда вы используете HttpClient.PostAsync(..).Result, ввод/вывод запускается (асинхронно), а вызывающий поток (синхронно) блокирует его до завершения.

Я обычно рекомендую, чтобы люди использовали await, а не Task.Result или Task.Wait по следующим причинам:

  • Если вы заблокируете Task, который является результатом метода async, вы можете легко войти в ситуацию взаимоблокировки.
  • Task.Result и Task.Wait завершают любые исключения в AggregateException (поскольку эти API-интерфейсы являются задержками с TPL). Поэтому обработка ошибок сложнее.

Однако, если вы знаете об этих ограничениях, есть ситуации, когда блокировка на Task может быть полезна (например, в приложении консоли Main).

Ответ 2

Захват результата задачи блокирует текущий поток. В этом случае нет смысла использовать асинхронную версию метода. Post() и PostAsync().Result будут блокированы.

Если вы хотите использовать concurrency, вы должны записать его как таковой:

async Task PostContent()
{
  var client = new HttpClient();
  Task t = await client.PostAsync("http://someservice/", someContent);
  //code after this line will execute when the PostAsync completes.
  return t;
}

Так как PostContent() сам возвращает задачу, метод, вызывающий ее, также должен ждать.

async void ProcessResult()
{
   var result = await PostContent(); 
   //Do work with the result when the result is ready 
}

Например, если вы вызываете ProcessResult() в обработчик нажатия кнопки, вы видите, что пользовательский интерфейс все еще реагирует, другие элементы управления все еще функционируют.