.net async - ¿Cuál es el propósito de "return await" en C#?




ejemplos create (6)

Si no necesita la async (es decir, puede devolver la Task directamente), entonces no use async .

Hay algunas situaciones en las que el return await es útil, como si tuviera dos operaciones asincrónicas que hacer:

var intermediate = await FirstAsync();
return await SecondAwait(intermediate);

Para obtener más información sobre el rendimiento de async , consulte el artículo y el video MSDN de Stephen Toub sobre el tema.

Actualización: He escrito una publicación de blog que entra en mucho más detalle.

¿Hay algún escenario donde escribir un método como este?

public async Task<SomeResult> DoSomethingAsync()
{
    // Some synchronous code might or might not be here... //
    return await DoAnotherThingAsync();
}

en lugar de esto:

public Task<SomeResult> DoSomethingAsync()
{
    // Some synchronous code might or might not be here... //
    return DoAnotherThingAsync();
}

tendría un sentido?

¿Por qué usar return await construcción cuando puede devolver directamente la Task<T> de la DoAnotherThingAsync() interna de DoAnotherThingAsync() ?

Veo el código con return await en tantos lugares, creo que debería haberme perdido algo. Pero por lo que entiendo, no usar palabras clave async / await en este caso y devolver directamente la tarea sería funcionalmente equivalente. ¿Por qué agregar una sobrecarga adicional de capa de await adicional?


Esto también me confunde y siento que las respuestas anteriores pasaron por alto su pregunta real:

¿Por qué utilizar return aguarice construir cuando puede devolver Tarea directamente desde la invocación DoAnotherThingAsync () interna?

Bueno, a veces quieres una Task<SomeType> , pero la mayoría de las veces realmente quieres una instancia de SomeType , es decir, el resultado de la tarea.

De tu código:

async Task<SomeResult> DoSomethingAsync()
{
    using (var foo = new Foo())
    {
        return await foo.DoAnotherThingAsync();
    }
}

Una persona que no Task<SomeResult> familiarizada con la sintaxis (yo, por ejemplo) podría pensar que este método debería devolver una Task<SomeResult> , pero dado que está marcado con async , significa que su tipo de devolución real es SomeResult . Si solo usa return foo.DoAnotherThingAsync() , estaría devolviendo una Tarea, que no se compilaría. La forma correcta es devolver el resultado de la tarea, por lo que la return await .


Otro caso que puede necesitar para esperar el resultado es este:

async Task<IFoo> GetIFooAsync()
{
    return await GetFooAsync();
}

async Task<Foo> GetFooAsync()
{
    var foo = await CreateFooAsync();
    await foo.InitializeAsync();
    return foo;
}

En este caso, GetIFooAsync() debe esperar el resultado de GetFooAsync porque el tipo de T es diferente entre los dos métodos y Task<Foo> no se puede Task<IFoo> directamente a Task<IFoo> . Pero si espera el resultado, simplemente se convierte en Foo que se puede IFoo directamente a IFoo . Luego, el método asíncrono simplemente Task<IFoo> a empaquetar el resultado dentro de la Task<IFoo> y listo.


La única razón por la que querría hacerlo es si hay alguna otra await en el código anterior, o si de alguna manera está manipulando el resultado antes de devolverlo. Otra forma en que eso podría estar sucediendo es a través de un try/catch que cambia la manera en que se manejan las excepciones. Si no está haciendo nada de eso, entonces tiene razón, no hay ninguna razón para agregar la sobrecarga de hacer que el método sea async .


Hacer el método asincrónico "thunk", que de otro modo sería simple, crea una máquina de estado asíncrona en la memoria mientras que la no asincrónica no. Si bien eso puede indicarles a las personas que utilicen la versión no asincrónica porque es más eficiente (lo que es cierto), también significa que, en caso de bloqueo, no hay evidencia de que ese método esté involucrado en la "pila de retorno / continuación". lo que a veces hace que sea más difícil entender el hang.

Así que sí, cuando el rendimiento no es crítico (y generalmente no lo es) voy a lanzar una sincronización en todos estos métodos de procesador para que tenga la máquina de estado asíncrona que me ayude a diagnosticar cuelgues más tarde, y también para ayudar a garantizar que esos Los métodos thunk siempre evolucionan con el tiempo, y se asegurarán de devolver las tareas con errores en lugar de throw.


Cuando se usa async y await el compilador genera una máquina de estado en segundo plano.

Aquí hay un ejemplo en el que espero poder explicar algunos de los detalles de alto nivel que están ocurriendo:

public async Task MyMethodAsync()
{
    Task<int> longRunningTask = LongRunningOperationAsync();
    // independent work which doesn't need the result of LongRunningOperationAsync can be done here

    //and now we call await on the task 
    int result = await longRunningTask;
    //use the result 
    Console.WriteLine(result);
}

public async Task<int> LongRunningOperationAsync() // assume we return an int from this long running operation 
{
    await Task.Delay(1000); // 1 second delay
    return 1;
}

OK, entonces, ¿qué pasa aquí?

  1. Task<int> longRunningTask = LongRunningOperationAsync(); comienza a ejecutar LongRunningOperation

  2. El trabajo independiente se realiza en Asumamos el hilo principal (Thread ID = 1) y luego await longRunningTask se llegue a await longRunningTask .

    Ahora, si longRunningTask no ha finalizado y aún se está ejecutando, MyMethodAsync() volverá a su método de llamada, por lo que el hilo principal no se bloqueará. Cuando longRunningTask , un subproceso de ThreadPool (puede ser cualquier subproceso) volverá a MyMethodAsync() en su contexto anterior y continuará la ejecución (en este caso, imprimiendo el resultado en la consola).

Un segundo caso sería que longRunningTask ya ha finalizado su ejecución y el resultado está disponible. Cuando await longRunningTask la await longRunningTask , ya tenemos el resultado, por lo que el código continuará ejecutándose en el mismo hilo. (en este caso imprimiendo resultado a consola). Por supuesto, este no es el caso del ejemplo anterior, donde hay un Task.Delay(1000) involucrado.





c# .net .net-4.5 async-await