Criar uma tarefa concluída

197

Quero criar um arquivo concluído Task(nãoTask<T> ). Existe algo embutido no .NET para fazer isso?

Uma pergunta relacionada: Crie uma tarefa concluída <T>

Timothy Shields
fonte
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.Que problemas você acha que isso tem? Se você armazenar em cache um único Task, todo o seu programa ocupará um pouco mais de memória. Isso não é nada . Além disso, pode-se criar uma tarefa concluída sem fazer isso, simplesmente não seria melhor.
Servy
10
Oh, minha decepção não tem nada a ver com ter que usar memória extra. Os valores do lixo em qualquer lugar do código não são elegantes.
Timothy Shields
1
Observe que hoje existem ValueTasktarefas concluídas (ou seja, valores que você já possui para que o código seja essencialmente síncrono), o que salvará uma alocação.
Nawfal # 28/18

Respostas:

247

A versão mais recente do .Net (v4.6) está adicionando exatamente isso, um Task.CompletedTask interno :

Task completedTask = Task.CompletedTask;

Essa propriedade é implementada como um singleton sem bloqueio, então você quase sempre usaria a mesma tarefa concluída.

i3arnon
fonte
1
Apenas verifiquei o CTP do VS 14 mais recente e criei um projeto 4.5.3, Task.CompletedTaskainda é interno.
Peter Ritchie #
1
2. Você não baixou o CTP mais recente (que é 4 e está vinculado a esse site) ou não especificou a versão 4.5.3. Aqui está o que está na minha máquina . @PeterRitchie
i3arnon
Criei uma VM a partir da imagem do Visual Studio 14 no Azure.
Peter Ritchie #
1
@PeterRitchie Do modelo VS14CTP4 do Azure
i3arnon 14/14
Estou trabalhando no Mac OS X com o mono 5.4.1.7 e recebo o mesmo erro. Como posso consertar isso?
precisa saber é o seguinte
153

Task<T>é implicitamente conversível em Task, portanto, basta obter um preenchimento Task<T>(com todo Te qualquer valor) e usá-lo. Você pode usar algo assim para ocultar o fato de que um resultado real existe, em algum lugar.

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

Observe que, como não estamos expondo o resultado e a tarefa está sempre concluída, podemos armazenar em cache uma única tarefa e reutilizá-la.

Se você estiver usando o .NET 4.0 e não o tiver FromResult, poderá criar seu próprio usando TaskCompletionSource:

public static Task<T> FromResult<T>(T value)
{
    var tcs = new TaskCompletionSource<T>();
    tcs.SetResult(value);
    return tcs.Task;
}
Servy
fonte
8
Se você estiver usando 4.0, você pode adicionar a biblioteca Microsoft.Bcl.Async para obter TaskEx.FromResult, bem como outras coisas úteis como WhenAll
Carl
@Servy O que muda de FromResult (false) e FromResult (true)?
Francesco Bonizzi
3
@FrancescoB. Se você estiver olhando para o resultado, ele altera o valor booleano do resultado. Se você está ignorando o resultado, o resultado é irrelevante.
Servy
66

Meu método preferido para fazer isso é chamar Task.WhenAll()sem argumentos. A documentação do MSDN informa que "Se o array / enumerável fornecido não contiver tarefas, a tarefa retornada fará a transição imediatamente para um estado RanToCompletion antes de retornar ao chamador". Parece o que você quer.

Atualização: Encontrei a fonte na Fonte de Referência da Microsoft ; lá você pode ver que Task.WhenAll contém o seguinte:

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

Portanto, Task.CompletedTask é realmente interno, mas é exposto chamando WhenAll () sem argumentos.

Richiban
fonte
9
embora pareça meio hacky, ele tem o apoio dos documentos, então não sei, eu meio que gosto!
Sara
2
Para mim e meu código restrito do .NET 4.5.2, é elegante o suficiente. Obrigado!
Stas Ivanov
36

Eu usaria Task.Delay(0). Internamente, ele retorna uma instância em cache de uma conclusão Task<T>. É exatamente o que a resposta atual sugere que seja feita, mas agora você não precisa armazenar em cache uma instância por conta própria nem possui valores de lixo deselegantes em seu código.

Você pode estar pensando que pode usar Task.Yield(), mas o resultado de nãoTask.Yield() é um subtipo de , enquanto o resultado de é. Essa é uma das diferenças sutis entre os dois.TaskTask.Delay(0)

gzak
fonte
30

Você pode usar Task.FromResult (no .NET 4.5) para retornar um resultado concluído Task<T>.

Se você precisar de um não genérico Task, poderá sempre usar Task.FromResult(0)ou semelhante, pois Task<T>é uma subclasse de Task.

Reed Copsey
fonte
11

Para o uso do .Net 4.6 e superior

return Task.CompletedTask;

Para a versão inferior, você pode usar

return new Task(() => { });
Icen
fonte
3
Para a abordagem pré 4.6, cuidado! Você precisa iniciar a tarefa ou ela nunca será concluída! Que tal usar return Task.Delay(0);?
Miquel #
0

E se:

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

Você pode deixar de fora a supressão de aviso se não se importar.

Dorus
fonte
Acredito que a marcação de um método asyncainda cria todo o aparelho da máquina de estado, mesmo que você não o utilize, portanto, retornar uma tarefa vazia é mais eficiente para cenários de baixo recurso.
Calvin Fisher