Створіть виконане завдання


197

Я хочу створити завершений Task(не Task<T>). Чи є щось вбудоване в .NET для цього?

Пов'язане запитання: Створіть виконане завдання <T>


2
It seems like the answer I'm getting from everyone is that using a garbage value like this is the correct way. That there isn't a way to do this without the garbage value is disappointing -- oh well.Які проблеми, на вашу думку, це має? Якщо ви кешуєте сингл, Taskто вся ваша програма займає один додатковий біт пам'яті. Це нічого . Крім того, можна створити виконане завдання, не роблячи цього, краще не було б.
Сервіс

10
О, моє розчарування не має нічого спільного з тим, що потрібно використовувати додаткову пам'ять. Просто значення сміття де-небудь у коді не є елегантними.
Тимофій Шилдс

1
Зауважте, що сьогодні є ValueTaskвиконані завдання (тобто для значень, які ви вже маєте, щоб код був по суті синхронним), що заощадить вам розподіл.
nawfal

Відповіді:


246

Нова версія .Net (v4.6) додає тільки що, вбудований в Task.CompletedTask :

Task completedTask = Task.CompletedTask;

Це властивість реалізується як одноблоковий без блокування, тому ви майже завжди використовуєте одне і те ж виконане завдання.


1
Щойно перевірив останню VS 14 CTP і створив проект 4.5.3, Task.CompletedTaskвсе ще внутрішній.
Пітер Річі

1
2. Або ви не завантажили останній CTP (який 4 і пов’язаний з цим сайтом), або ви не вказали версію 4.5.3. Ось що на моїй машині . @PeterRitchie
i3arnon

Я створив VM з зображення Visual Studio 14 на Azure.
Пітер Річі


Я працюю над Mac OS X з моно 5.4.1.7, і я отримую цю саму помилку. Як я можу це виправити?
Халед Аннахар

152

Task<T>конвертовано неявно Task, тому просто отримайте завершений Task<T>(з будь-яким Tі будь-яким значенням) і використовуйте це. Ви можете використовувати щось подібне, щоб приховати той факт, що фактичний результат десь є.

private static Task completedTask = Task.FromResult(false);
public static Task CompletedTask()
{
    return completedTask;
}

Зауважте, що оскільки ми не виставляємо результат, і завдання завжди виконується, ми можемо кешувати одне завдання і повторно використовувати його.

Якщо ви використовуєте .NET 4.0, а у вас немає, FromResultви можете створити свій власний, використовуючи TaskCompletionSource:

public static Task<T> FromResult<T>(T value)
{
    var tcs = new TaskCompletionSource<T>();
    tcs.SetResult(value);
    return tcs.Task;
}

8
Якщо ви використовуєте 4.0, ви можете додати бібліотеку Microsoft.Bcl.Async, щоб отримати TaskEx.FromResult, а також інші зручні речі, такі як WhenAll
Carl

@ Сервіс Що змінюється на FromResult (помилковий) та FromResult (справжній)?
Франческо Боніцці

3
@FrancescoB. Якщо ви коли-небудь дивитесь на результат, то це змінює бульне значення результату. Якщо ви ігноруєте результат, то те, що є результатом, не має значення.
Сервіс

66

Моїм кращим методом для цього є дзвінки Task.WhenAll()без аргументів. Документація MSDN зазначає, що "Якщо наданий масив / перелік не містить завдань, повернене завдання негайно перейде в стан RanToCompletion, перш ніж воно буде повернене до абонента." Це звучить як те, що ти хочеш.

Оновлення: я знайшов джерело у довідковому джерелі Microsoft ; там ви бачите, що Task.WhenAll містить таке:

return (tasks.Length == 0) ? // take shortcut if there are no tasks upon which to wait
            Task.CompletedTask :
            new WhenAllPromise(tasks);

Отже, Task.CompletedTask дійсно є внутрішнім, але він відкривається, викликаючи WhenAll () без аргументів.


9
в той час як це НЕ відчуває себе хакі, у нього є підтримка від документів, тому я не знаю, мені це подобається!
сара

2
Для мене та мого .NET 4.5.2 обмеженого коду він досить елегантний. Дякую!
Стас Іванов

36

Я б користувався Task.Delay(0). Внутрішньо він повертає кешований екземпляр завершеного Task<T>. Це саме те, що пропонує нинішня відповідь зробити так чи інакше, тільки тепер вам не потрібно самостійно кешувати екземпляр, а також не маєте неелегантних значень сміття у своєму коді.

Ви можете подумати , ви можете використовувати Task.Yield()замість цього, але виявляється , що результат в Task.Yield()це НЕ підтип Task, а результат Task.Delay(0)є. Це одна з найтонших відмінностей між ними.


30

Ви можете використовувати Task.FromResult (в .NET 4.5) для повернення завершеного Task<T>.

Якщо вам потрібен не-загальний Task, ви завжди можете використовувати Task.FromResult(0)або подібне, оскільки Task<T>це підклас Task.


11

Для використання .Net 4.6 та вище

return Task.CompletedTask;

Для нижчої версії ви можете використовувати

return new Task(() => { });

3
Для попереднього підходу 4.6, обережно! Потрібно запустити завдання, інакше воно ніколи не завершиться! Як щодо використання return Task.Delay(0);натомість?
Мікель


0

Як щодо:

#pragma warning disable 1998
    public async Task emptyTask() {
    }
#pragma warning restore 1998

Якщо ви не заперечуєте проти цього, ви можете залишити попередження придушення.


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