Яке використання Task.FromResult <TResult> у C #


189

У C # і TPL ( бібліотека паралельних завдань ) Taskклас представляє роботу, що триває, що створює значення типу T.

Я хотів би знати, у чому полягає потреба у методі Task.FromResult ?

Тобто: У сценарії, коли у вас вже є отримана цінність під рукою, у чому полягає необхідність повернути її в завдання?

Єдине, що спадає на думку, це те, що він використовується як якийсь адаптер для інших методів, що приймають екземпляр Task.



30
Я певною мірою згоден з цим, але створення щільних, корисних, консолідованих сторінок, орієнтованих на дискусію, як це, є величезною вигодою. Я майже завжди довідаюся більше на гарній, щільній сторінці stackoverflow, ніж на гуглінгу та дослідженні в різних місцях, тому в цьому випадку я дуже радий, що він опублікував це.
Алекс Едельштайн

41
Я думаю, що 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 hmhm, дякую за пояснення. Я припускав, що очікування нерестується, але я спробував це, і я бачу, що це не так. Тільки Task.Run робить. Тому x = очікуємо Task.FromResult (0); еквівалентно вимові x = 0; це заплутано, але добре знати!
Джон Генкель

4
@OlegI: Найкращим рішенням для операцій вводу / виводу є його реалізація асинхронно, але іноді у вас немає такого вибору. Крім того, іноді ви можете реалізувати його синхронно (наприклад, кешований результат, повертаючись до асинхронної реалізації, якщо значення не кешоване). Більш загально, Taskметод -повернення означає " може бути асинхронним". Тому іноді методам надається асинхронний підпис, добре знаючи, що деякі реалізації будуть синхронними (наприклад, NetworkStreamповинні бути асинхронні, але MemoryStreamповинні бути синхронізованими).
Стівен Клірі

50

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

Приклад кешу: Приклад кешу, використовуючи Task.FromResult для попередньо обчислених значень


А завершені завдання, наприклад ті, що повернулися з Task.FromResult, можна кешувати.
Paulo Morgado

1
@Paulo: зберігання всього об’єкта Task в пам'яті здається набагато марнішим, ніж кешування лише результату.
Ben Voigt

2
Очікуйте, що "завдання на значення" вже кешовані. Я не пам'ятаю точно , які з них, але я думаю Task.FromResult(0), Task.FromResult(1), Task.FromResult(false)і Task.FromResult(true)кешуються. Ви не повинні кешувати завдання для доступу до мережі, але одне з результатів ідеально добре. Чи бажаєте ви створити його кожен раз, коли вам потрібно повернути значення?
Пауло Моргадо

4
... і щоб відповісти на моє власне запитання, користь кешу завдань полягає в тому, що деякі з них можуть бути виконаними завданнями, а інші - такими, які ще не закінчені. Абонентам не потрібно дбати: вони роблять асинхронний дзвінок, і якщо він вже завершений, вони отримують відповідь негайно, коли чекають, якщо ні, вони отримують це пізніше. Без цих кешованих завдань або (а) потрібні два різні механізми, одна синхронізація та одна асинхроніка - громіздка для абонента, або (b) доведеться динамічно створювати завдання, кожен раз, коли абонент запитує відповідь, яка вже доступна (якщо ми кешували лише TResult).
ToolmakerSteve

1
Я зараз це розумію. Формулювання відповіді було дещо заплутаним. Сама задача не має вбудованого механізму "кешування". Але якщо ви написали механізм кешування для ... скажімо .... завантаження файлів, Завдання <File> GetFileAync (), ви можете миттєво повернути файл, який уже є в кеші, використовуючи Task.FromResult (cachedFile) та очікуючи буде працювати синхронно, економлячи час, не маючи потокового перемикача.
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 Action. Очікується, що метод ExecuteAsync буде асинхронним, але вам не потрібно використовувати ключове слово async, щоб зробити його асинхронним та очікуваним. Оскільки ви вже маєте результат і не потрібно нічого чекати, краще скористатися Task.FromResult.



4

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


у вашому хорошому зразку результат не в руці синхронно, операція - все асинхронізація, Task.FromResultвикористовується для отримання раніше кешованого результату асинхронізації.
Родріго Рейс

1

Я заперечую, що ви можете використовувати Task.FromResult для синхронних методів, які потребують тривалого часу, тоді як ви можете виконувати іншу незалежну роботу у своєму коді. Я скоріше змушу ці методи викликати асинхронізацію. Але уявіть ситуацію, коли у вас немає контролю над кодом, що називається, і ви хочете, щоб неявна паралельна обробка.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.