Какая польза для Task.FromResult <TResult> в C #

189

В C # и TPL ( Task Parallel Library ) Taskкласс представляет собой текущую работу, которая создает значение типа T.

Я хотел бы знать, что нужно для метода Task.FromResult ?

То есть: в сценарии, где у вас уже есть произведенная ценность, зачем нужно возвращать ее в задачу?

Единственное, что приходит на ум, это то, что он используется как какой-то адаптер для других методов, принимающих экземпляр Task.

лизергиновой кислоты
источник
4
тебе это помогает? msdn.microsoft.com/en-us/library/hh228607.aspx
Изикон,
30
В какой-то степени я согласен с этим, но создание таких плотных, полезных, консолидированных, ориентированных на обсуждение страниц, как это, является огромным преимуществом. Я почти всегда учусь на хорошей, плотной странице стекаповоротов, чем на поиске и поиске в разных местах, поэтому в этом случае я действительно рад, что он опубликовал это.
Алекс Эдельштейн
42
Я думаю, что Google приводит меня к ТАК и ТАК просит меня перейти на Google. Это круговая ссылка :)
пользователь gmail

Ответы:

258

Я нашел два варианта использования:

  1. Когда вы реализуете интерфейс, который допускает асинхронные вызовы, но ваша реализация является синхронной.
  2. Когда вы заглушаете / высмеиваете асинхронный код для тестирования.
Стивен Клири
источник
6
Хорошим примером для №1 является веб-сервис. У вас может быть синхронный метод обслуживания, который возвращает, Task.FromResultи клиент, который ожидает асинхронно для сетевого ввода-вывода. Таким образом, вы можете использовать один и тот же интерфейс между клиентом и сервером, используя ChannelFactory.
Нельсон Ротермел
2
Например, метод ChallengeAsync. WTF думали дизайнеры из MS? У этого метода нет абсолютно никаких причин возвращать Задачу. И весь пример кода от MS просто имеет FromResult (0). Надеемся, что компилятор достаточно умен, чтобы оптимизировать это, и на самом деле не создает новый поток, а затем сразу же его убивает!
Джон Хенкель
14
@JohnHenckel: OWIN разработан с нуля, чтобы быть асинхронным. Интерфейсы и базовые классы часто используют асинхронные подписи, потому что это только позволяет (не заставляет ) реализацию быть асинхронной. Так что это похоже на IEnumerable<T>наследование IDisposable- оно позволяет перечисляемым иметь одноразовые ресурсы, а не заставляет их. Ни FromResult, asyncни awaitтемы не будут порождены.
Стивен Клири
4
@StephenCleary хм, спасибо, что объяснили это. Я предполагал, что ожидание будет порождаться, но я попробовал это, и я вижу, что это не так. Только Task.Run делает. Следовательно, x = await Task.FromResult (0); эквивалентно высказыванию х = 0; это сбивает с толку, но приятно знать!
Джон Хенкель
4
@OlegI: для операций ввода-вывода лучшее решение - реализовать его асинхронно, но иногда у вас нет такого выбора. Кроме того, иногда вы можете реализовать его синхронно (например, кэшированный результат, возвращаясь к асинхронной реализации, если значение не кэшируется). В более общем смысле « Taskвозвратный метод» означает « может быть асинхронным». Поэтому иногда методы получают асинхронную сигнатуру, прекрасно зная, что некоторые реализации будут синхронными (например, NetworkStreamдолжны быть асинхронными, но MemoryStreamдолжны быть синхронизированы).
Стивен Клири
50

Одним из примеров будет метод, который использует кэш. Если результат уже вычислен, вы можете вернуть выполненное задание со значением (используя Task.FromResult). Если это не так, то вы продолжаете и возвращаете задачу, представляющую текущую работу.

Пример кэширования: пример кэширования с использованием Task.FromResult для предварительно вычисленных значений

Мэтт Смит
источник
И выполненные задачи, такие как возвращенные Task.FromResult, могут быть кэшированы.
Пауло Моргадо
1
@Paulo: хранение всего объекта Task в памяти кажется гораздо более расточительным, чем кэширование только результата.
Бен Фойгт
2
Ожидайте, что «задачи значения» уже кэшированы. Я не помню точно , какие из них, но я думаю Task.FromResult(0), Task.FromResult(1), Task.FromResult(false)и Task.FromResult(true)кэшируются. Вы не должны кэшировать задачу для доступа к сети, но одна из результатов отлично подходит. Вы бы предпочли создавать его каждый раз, когда вам нужно вернуть значение?
Пауло Моргадо
4
... и, отвечая на мой собственный вопрос, преимущество кэша задач состоит в том, что некоторые из них могут быть завершены, а другие могут быть еще не завершенными. Абонентам не нужно заботиться: они выполняют асинхронный вызов, и, если он уже завершен, они получают ответ немедленно, когда ожидают, а если нет, то получают его позже. Без этих кэшированных задач, либо (а) потребуется два разных механизма, один синхронизирующий и один асинхронный - громоздкий для вызывающей стороны, либо (б) необходимо динамически создавать задачу, каждый раз, когда вызывающий абонент запрашивает ответ, который уже доступен (если мы только кэшировали TResult).
ToolmakerSteve
1
Я понял теперь. Формулировка ответа была немного запутанной. Само задание не имеет встроенного механизма «кэширования». Но если вы написали механизм кэширования для ... скажем .... загрузки файлов, Task <File> GetFileAync (), вы могли бы мгновенно вернуть файл, который уже находится в кеше, с помощью Task.FromResult (cachedFile) и средства await. будет работать синхронно, экономя время, не имея переключателя потока.
Brain2000
31

Используйте его, когда вы хотите создать ожидаемый метод без использования ключевого слова async. Я нашел этот пример:

public class TextResult : IHttpActionResult
{
    string _value;
    HttpRequestMessage _request;

    public TextResult(string value, HttpRequestMessage request)
    {
        _value = value;
        _request = request;
    }
    public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
    {
        var response = new HttpResponseMessage()
        {
            Content = new StringContent(_value),
            RequestMessage = _request
        };
        return Task.FromResult(response);
    }
}

Здесь вы создаете собственную реализацию интерфейса IHttpActionResult для использования в действии Web Api. Ожидается, что метод ExecuteAsync будет асинхронным, но вам не нужно использовать ключевое слово async, чтобы сделать его асинхронным и ожидаемым. Поскольку у вас уже есть результат и вам не нужно ничего ждать, лучше использовать Task.FromResult.

Edminsson
источник
4

Используйте Task.FromResult, когда вы хотите выполнить асинхронную операцию, но иногда результат находится в руках синхронно. Вы можете найти хороший образец здесь http://msdn.microsoft.com/en-us/library/hh228607.aspx .

Alborz
источник
в вашем хорошем примере результат не находится в руках синхронно, все операции асинхронные, они Task.FromResultиспользуются для получения ранее кэшированного асинхронного результата.
Родриго Рейс
1

Я бы сказал, что вы можете использовать Task.FromResult для синхронных методов, выполнение которых занимает много времени, в то время как вы можете выполнять другую независимую работу в своем коде. Я бы предпочел, чтобы эти методы вызывали async. Но представьте себе ситуацию, когда у вас нет контроля над вызываемым кодом, и вы хотите эту неявную параллельную обработку.

викинг
источник