Crear una tarea completada

197

Quiero crear un completado Task(no Task<T>). ¿Hay algo integrado en .NET para hacer esto?

Una pregunta relacionada: Crear una tarea completada <T>

Timothy Shields
fuente
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.¿Qué problemas crees que tiene esto? Si almacena un solo caché, Tasktodo su programa ocupa un bit adicional de memoria. Eso es nada . Además, uno podría crear una tarea completa sin hacer eso, simplemente no sería mejor.
Servy
10
Oh, mi decepción no tiene nada que ver con tener que usar memoria extra. Es solo que los valores basura en cualquier parte del código no son elegantes.
Timothy Shields el
1
Tenga en cuenta que hoy hay ValueTasktareas completadas (es decir, valores que ya tiene para que el código sea esencialmente sincrónico), lo que le ahorrará una asignación.
nawfal

Respuestas:

247

La versión más reciente de .Net (v4.6) está agregando justamente eso, una tarea incorporada .

Task completedTask = Task.CompletedTask;

Esa propiedad se implementa como un singleton sin bloqueo, por lo que casi siempre usaría la misma tarea completada.

i3arnon
fuente
1
Solo revisé el último VS 14 CTP y creé un proyecto 4.5.3, Task.CompletedTasktodavía es interno.
Peter Ritchie
1
2. O no ha descargado el último CTP (que es 4 y está vinculado desde ese sitio) o no ha especificado la versión 4.5.3. Esto es lo que hay en mi máquina . @PeterRitchie
i3arnon
Creé una máquina virtual a partir de la imagen de Visual Studio 14 en Azure.
Peter Ritchie
1
@PeterRitchie De la plantilla Azure VS14CTP4
i3arnon
Estoy trabajando en Mac OS X con mono 5.4.1.7 y obtengo este mismo error. ¿Cómo puedo arreglar esto?
Khaled Annajar
153

Task<T>es implícitamente convertible a Task, así que solo obtenga un completado Task<T>(con Tcualquier valor) y úselo. Puede usar algo como esto para ocultar el hecho de que un resultado real está allí, en alguna parte.

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

Tenga en cuenta que dado que no estamos exponiendo el resultado, y la tarea siempre se completa, podemos almacenar en caché una sola tarea y reutilizarla.

Si está utilizando .NET 4.0 y no lo tiene FromResult, puede crear el suyo usandoTaskCompletionSource :

public static Task<T> FromResult<T>(T value)
{
    var tcs = new TaskCompletionSource<T>();
    tcs.SetResult(value);
    return tcs.Task;
}
Servy
fuente
8
Si está utilizando 4.0, puede agregar la biblioteca Microsoft.Bcl.Async para obtener TaskEx.FromResult, así como otras cosas útiles como WhenAll
Carl
@Servy ¿Qué cambia de FromResult (falso) y FromResult (verdadero)?
Francesco Bonizzi
3
@FrancescoB. Si alguna vez mira el resultado, entonces cambia el valor booleano del resultado. Si ignora el resultado, entonces el resultado es irrelevante.
Servy
66

Mi método preferido para hacer esto es llamar Task.WhenAll()sin argumentos. La documentación de MSDN establece que "Si la matriz / enumerable suministrada no contiene tareas, la tarea devuelta pasará inmediatamente a un estado RanToCompletion antes de que se devuelva al llamante". Eso suena como lo que quieres.

Actualización: encontré la fuente en la Fuente de referencia de Microsoft ; allí puede ver esa tarea. Cuando todo contiene lo siguiente:

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

Entonces Task.CompletedTask es de hecho interno, pero se expone llamando a WhenAll () sin argumentos.

Richiban
fuente
9
Si bien se siente un poco hacky, tiene el apoyo de los documentos, así que no sé, ¡me gusta!
Sara
2
Para mí y mi código restringido .NET 4.5.2 es lo suficientemente elegante. ¡Gracias!
Stas Ivanov
36

Me gustaría utilizar Task.Delay(0). Internamente, devuelve una instancia en caché de un completado Task<T>. Esto es exactamente lo que la respuesta actual sugiere hacer de todos modos, solo que ahora no tiene que almacenar en caché una instancia usted mismo, ni tiene valores de basura poco elegantes en su código.

Tal vez pienses que puedes usar Task.Yield() , pero resulta que el resultado de noTask.Yield() es un subtipo de , mientras que el resultado de es. Esa es una de las diferencias sutiles entre los dos.TaskTask.Delay(0)

gzak
fuente
30

Puede usar Task.FromResult (en .NET 4.5) para devolver un archivo completadoTask<T> .

Si necesita un no genérico Task, siempre puede usar Task.FromResult(0)o similar, ya que Task<T>es una subclase de Task.

Reed Copsey
fuente
11

Para uso .Net 4.6 y superior

return Task.CompletedTask;

Para la versión inferior puedes usar

return new Task(() => { });
Icen
fuente
3
Para el enfoque pre 4.6, ¡cuidado! ¡Necesita comenzar la tarea o nunca se completará! ¿Qué hay de usar en su return Task.Delay(0);lugar?
Miquel
0

Qué tal si:

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

Puede omitir la supresión de advertencia si no le importa.

Dorus
fuente
Creo que marcar un método asynctodavía crea todo el aparato de máquina de estado, incluso si no lo usa, por lo que devolver una tarea vacía es más eficiente para escenarios de bajos recursos.
Calvin Fisher