Cómo y cuándo usar 'async' y 'await'

Resuelto Dan Dinu asked hace 11 años • 26 respuestas

Según tengo entendido, una de las principales cosas que asynchacemosawait es hacer que el código sea fácil de escribir y leer, pero ¿usarlos es equivalente a generar subprocesos en segundo plano para realizar una lógica de larga duración?

Actualmente estoy probando el ejemplo más básico. Agregué algunos comentarios en línea. ¿Puedes aclararmelo?

// I don't understand why this method must be marked as `async`.
private async void button1_Click(object sender, EventArgs e)
{
    Task<int> access = DoSomethingAsync();
    // task independent stuff here

    // this line is reached after the 5 seconds sleep from 
    // DoSomethingAsync() method. Shouldn't it be reached immediately? 
    int a = 1; 

    // from my understanding the waiting should be done here.
    int x = await access; 
}

async Task<int> DoSomethingAsync()
{
    // is this executed on a background thread?
    System.Threading.Thread.Sleep(5000);
    return 1;
}
Dan Dinu avatar Jan 22 '13 16:01 Dan Dinu
Aceptado

Cuando se usa asyncy awaitel 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 sucediendo:

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;
}

Bien, entonces, ¿qué pasa aquí?

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

  2. Se realiza un trabajo independiente, supongamos que await longRunningTaskse alcanza el subproceso principal (ID de subproceso = 1).

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

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

Dan Dinu avatar Nov 14 '2013 18:11 Dan Dinu

Según tengo entendido, una de las cosas principales que hacen async y await es hacer que el código sea fácil de escribir y leer.

Su objetivo es hacer que el código asincrónico sea fácil de escribir y leer, sí.

¿Es lo mismo que generar subprocesos en segundo plano para realizar una lógica de larga duración?

De nada.

// No entiendo por qué este método debe marcarse como 'async'.

La asyncpalabra clave habilita la awaitpalabra clave. Por lo tanto, cualquier método que se utilice awaitdebe estar marcado async.

// Esta línea se alcanza después de 5 segundos de suspensión del método DoSomethingAsync(). ¿No debería alcanzarse de inmediato?

No, porque asynclos métodos no se ejecutan en otro hilo de forma predeterminada.

// ¿Esto se ejecuta en un hilo en segundo plano?

No.


Puede que mi async/ awaitintroducción te resulte útil. Los documentos oficiales de MSDN también son inusualmente buenos (particularmente la sección TAP ) y el asyncequipo publicó excelentes preguntas frecuentes .

Stephen Cleary avatar Jan 22 '2013 13:01 Stephen Cleary