Использование Task.FromResult v / s ждут в C # - PullRequest
0 голосов
/ 06 июня 2018

Я новичок в асинхронном программировании на C #, и мне нужно выяснить, является ли какой-либо из следующих способов предпочтительным для работы с объектом Task.

У меня есть класс, который делает это:

var value = this.SomeFunction(...);

var innerValue = await Task.FromResult(value.Result);

Somefunction выглядит как показано ниже.

protected async Task<JObject> Somefunction(..)
{
 ..
 returns JBoject
 ..
}

Это работает нормально, как и ожидалось.Теперь у меня есть предположение, что я не должен использовать Task.FromResult с async функциями.Вместо этого я должен использовать что-то вроде:

var innerValue = await value; //..this works fine too

Но я не совсем уверен, почему 1-й не является хорошей практикой для выполнения того же самого действия .Любые выводы будут полезны.Спасибо

Ответы [ 2 ]

0 голосов
/ 06 июня 2018

Давайте пройдемся по тому, что вы делаете, и скажем точно, почему это неправильно.

var value = this.SomeFunction(...);

Прежде всего: используйте var, когда тип либо чистый, либо неважный. Тип здесь неясен, и он важен .

Второе: имя функции, асинхронные с суффиксом Async.

Давайте исправим ваш пример.Это все еще неправильно, но теперь это более ясно:

Task<Toast> toastTask = this.StartToasterAsync();
Toast toast = await Task.FromResult(toastTask.Result);

Этот рабочий процесс совершенно неверен. Давайте переведем его на английский.Вот мой список дел на сегодня:

  • Положите немного хлеба в тостер.
  • Пока хлеб поджаривается, я мог бы выполнять другую работу, но вместо этого смотретьпока тостер ничего не делает, пока он не будет сделан .
  • Получите тост из тостера и создайте новый список дел.
  • Новый список дел: Получить кусок тоста, который я сейчас держу.
  • Выполнить этот список дел.Пока я жду, пока список дел завершится, иди делай другую работу, , но список дел всегда уже завершен, потому что задача состоит в том, чтобы получить результат, который я уже получил .Так что не занимайся другой работой.Просто проверьте, что да, я на самом деле держу кусок тоста, о котором я только что написал список дел.
  • Теперь у меня есть кусок тоста.

Этот рабочий процессбезумный способ сделать тост.Это работает - в конце вы получите кусочек тоста - но ни один разумный человек не сделает этого, и вам не следует писать эквивалентную компьютерную программу:

  • Это «асинхронный»рабочий процесс, в котором все возможные асинхронные преимущества были удалены .
  • Первый шаг - ожидание появления тостера - синхронно ожидался.
  • Второй шаг - асинхронное ожидание задачи, которая уже выполнена, никогда не бывает асинхронным!

Никогда никогда не пишите асинхронный код таким образом.

Правильный рабочий процесс для изготовления тоста:

  • Положите хлеб в тостер и начинайте его поджаривать.
  • Выполняйте другие работы, пока тост не лопнет.
  • Принесите тост.

И, как мы и ожидали, правильный способ написания вашей программы намного проще:

Task<Toast> toastTask = this.StartToasterAsync(...);
Toast toast = await toastTask;

Или даже лучше:

Toast toast = await this.StartToasterAsync(...);

Вы новичок в этом, и вы не усвоили значения различных операций в асинхронных рабочих процессах.Операции в вашей маленькой программе:

  • .Result означает, что перестает быть асинхронным и ничего не делает, пока не станет доступен результат .Обратите внимание, что это может вызвать взаимные блокировки .Вы останавливаете поток, пока не станет доступен результат; что если вы остановите поток, который собирался дать результат в будущем ?Представьте, например, что мы сделали список дел: «(1) Заказать коробку конфет из Интернета. (2) Ничего не делать, пока шоколад не прибудет. (3) Достать шоколад из почтового ящика».Этот рабочий процесс не завершается, поскольку существует синхронное ожидание результата, который требует от вас выполнения работы в будущем .
  • await означает , этот рабочий процесс не может продолжаться до тех пор, пока не будет получендоступно, так что асинхронно ждите его .Выйдите и найдите другую работу, и когда результат будет доступен, мы начнем снова здесь.

Обратите внимание, что оба они означают одно и то же, в этом оба являются точкамив рабочем процессе, где рабочий процесс не продолжается, пока не станет доступен результат .Но они совершенно разные в том смысле, что Result является синхронным ожиданием, а await является асинхронным ожиданием. Убедитесь, что вы понимаете это .Это самый фундаментальный момент, который вы должны понять.

И, наконец,

  • FromResult означает , кому-то нужна задача, но у меня уже есть результат этой задачи, поэтому сделайте задачу, которая уже выполнена .Когда он await ed или Result вызывается для него, в любом случае, он немедленно возвращает результат.

Это необычно для вызова FromResult.Если вы находитесь в асинхронном рабочем процессе, обычно вы просто return result; сообщаете, что задача выполнена.

0 голосов
/ 06 июня 2018

Проблема в первой версии не в использовании Task.FromResult, который из документации:

Создает Task<TResult>, который успешно завершен с указанным результатом

Проблема в вызове value.Result, который выполняет синхронное ожидание.Итак, вы по существу асинхронно ждете синхронного результата.

Обратите внимание, что первая версия является плохой оболочкой (из-за кода, который должен быть сгенерирован для вызова await) вокруг этого:

var value = this.SomeFunction(...);
var innerValue = value.Result;

Чтобы подвести итог, просто используйте это:

var innerValue = await value;

Или, если нет кода для запуска между value и innerValue, вы можете полностью игнорировать присвоение value

var innerValue = await this.SomeFunction(...);
...