2012-01-07 13 views
74

¿Podría alguien tener la amabilidad de confirmar si he entendido correctamente la palabra clave Async? (Utilizando la versión 3 del CTP)¿Async espera la palabra clave equivalente a un ContinueWith lambda?

Hasta ahora he descubierto que insertar la palabra clave await antes de una llamada a un método esencialmente hace 2 cosas, A. Crea un retorno inmediato y B. Crea una "continuación" que se invoca al completar la invocación del método async. En cualquier caso, la continuación es el resto del bloque de código para el método.

Entonces, lo que me pregunto es si estos dos bits de código son técnicamente equivalentes, y si es así, básicamente significa que la palabra clave await es idéntica a la de un ContinueWith Lambda (es decir, es básicamente un atajo de compilación) ? Si no es así, ¿cuáles son las diferencias?

bool Success = 
    await new POP3Connector(
     "mail.server.com", txtUsername.Text, txtPassword.Text).Connect(); 
// At this point the method will return and following code will 
// only be invoked when the operation is complete(?) 
MessageBox.Show(Success ? "Logged In" : "Wrong password"); 

VS

(new POP3Connector(
    "mail.server.com", txtUsername.Text, txtPassword.Text).Connect()) 
.ContinueWith((success) => 
    MessageBox.Show(success.Result ? "Logged In" : "Wrong password")); 

Respuesta

73

La idea general es correcta - el resto del método se convierte en una continuación de las clases.

El "fast path" blog post tiene detalles sobre cómo funciona la transformación del compilador async/await.

Diferencias, de la parte superior de mi cabeza:

La palabra clave await también hace uso de un concepto de "contexto de programación". El contexto de programación es SynchronizationContext.Current si existe, cayendo de nuevo en TaskScheduler.Current. La continuación se ejecuta en el contexto de programación. Así que una aproximación más cercana sería pasar TaskScheduler.FromCurrentSynchronizationContext en ContinueWith, retrocediendo en TaskScheduler.Current si es necesario.

La implementación real de async/await se basa en la coincidencia de patrones; usa un patrón "a la espera" que permite esperar otras cosas además de las tareas. Algunos ejemplos son las API asíncronas WinRT, algunos métodos especiales como Yield, Rx observables y special socket awaitables that don't hit the GC as hard. Las tareas son poderosas, pero no son las únicas esperables.

Nos viene a la mente una pequeña y pequeña diferencia: si el tiempo de espera ya está completo, entonces el método async en realidad no regresa en ese punto; continúa sincrónicamente Por lo tanto, es como pasar TaskContinuationOptions.ExecuteSynchronously, pero sin los problemas relacionados con la pila.

+2

muy bien dicho - Intento deferirme a las publicaciones de Jon, ya que son mucho más extensas que cualquier cosa que tuviera tiempo de poner en una respuesta en SO, pero Stephen tiene toda la razón. WRT lo que está a la espera (y GetAwaiter en particular), su publicación # 3 es muy útil en mi humilde opinión :) http://msmvps.com/blogs/jon_skeet/archive/2011/05/13/eduasync-part-3-the-shape- of-the-async-method-awaitable-boundary.aspx –

+4

El lugar de Stephen aquí. Para ejemplos simples, es fácil pensar que async/await es solo un atajo para ContinueWith; sin embargo, me gusta pensarlo en el reverso. Async/await es en realidad una expresión más poderosa de lo que solía usar ContinueWith para. El problema es que ContinueWith (...) usa lambdas y permite que la ejecución se transfiera a la continuación, pero otros conceptos de flujo de control como bucles son bastante imposibles si tiene que poner la mitad del cuerpo del bucle antes que el ContinueWith (... .) y la otra mitad después. Terminas con el encadenamiento de continuación manual. –

+7

Otro ejemplo donde async/await es mucho más expresivo que ContinueWith (...) está fluyendo excepciones. Puede esperar varias veces dentro del mismo bloque de prueba, y para cada etapa de ejecución, sus excepciones se pueden canalizar al mismo bloque catch (...) sin tener que escribir toneladas de código que lo hagan explícitamente. –

8

Es "esencialmente", pero el código generado hace estrictamente más que eso. Para las porciones más detalle en el código generado, lo recomiendo mucho la serie Eduasync de Jon Skeet:

http://codeblog.jonskeet.uk/category/eduasync/

En particular, puesto # 7 se mete en lo que se genera (a partir de CTP 2) y por qué, así que probablemente un gran ajuste para lo que está buscando en la actualidad

http://codeblog.jonskeet.uk/2011/05/20/eduasync-part-7-generated-code-from-a-simple-async-method/

EDIT: Creo que es probable que sea más detalle de lo que se está buscando de la pregunta, pero si usted se está preguntando qué aspecto tienen las cosas cuando tienes múltiples esperanzas en el método, eso está cubierto en la publicación # 9 :)

http://codeblog.jonskeet.uk/2011/05/30/eduasync-part-9-generated-code-for-multiple-awaits/

Cuestiones relacionadas