Создать завершенную задачу


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файл, тогда вся ваша программа занимает один дополнительный бит памяти. Это ничего . Кроме того, можно создать завершенную задачу, не делая этого, просто не будет ничего лучше.
Serv

10
О, мое разочарование не имеет ничего общего с необходимостью использования дополнительной памяти. Просто значения мусора в любом месте кода не элегантны.
Тимоти Шилдс

1
Обратите внимание, что сегодня есть ValueTaskдля завершенных задач (то есть для значений, которые у вас уже есть, так что код является по существу синхронным), что сэкономит вам распределение.
Nawfal

Ответы:


247

В новейшей версии .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

Я создал виртуальную машину из образа Visual Studio 14 в Azure.
Питер Ричи


Я работаю на Mac OS X с моно 5.4.1.7, и я получаю эту же ошибку. Как я могу это исправить?
Халед Аннажар

153

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

@Servy Что это меняет от FromResult (false) и FromResult (true)?
Франческо Боницци

3
@FrancescoB. Если вы когда-либо смотрите на результат, то это изменит логическое значение результата. Если вы игнорируете результат, то что это за результат, не имеет значения.
Serv

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.