c# - ¿Async espera la palabra clave equivalente a un ContinueWith lambda?
async-await continuations (2)
¿Podría alguien tener la amabilidad de confirmar si he entendido que Async aguarda correctamente la palabra clave? (Usando la versión 3 del CTP)
Hasta ahora he descubierto que insertar la palabra clave await antes de una llamada a un método esencialmente hace dos cosas, A. Crea una devolución inmediata y B. Crea una "continuación" que se invoca al completar la invocación del método asincrónico. 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í, ¿esto significa básicamente que la palabra clave await es idéntica a la de crear un ContinueWith Lambda (es decir, básicamente es un atajo de compilación para uno)? 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"));
Es "esencialmente" eso, pero el código generado hace estrictamente más que eso. Para obtener muchos más detalles sobre el código generado, recomiendo encarecidamente la serie Eduasync de Jon Skeet:
http://codeblog.jonskeet.uk/category/eduasync/
En particular, la publicación # 7 entra en lo que se genera (a partir de CTP 2) y por qué, así que probablemente sea una buena opción para lo que estás buscando en este momento:
http://codeblog.jonskeet.uk/2011/05/20/eduasync-part-7-generated-code-from-a-simple-async-method/
EDITAR: Creo que es probable que sea más detallado que lo que estás buscando de la pregunta, pero si te preguntas cómo son 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/
La idea general es correcta: el resto del método se convierte en una especie de continuación.
La publicación de blog "vía rápida" contiene detalles sobre cómo funciona la transformación del compilador async
/ await
.
Diferencias, fuera 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, volviendo a 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
, TaskScheduler.Current
a TaskScheduler.Current
si es necesario.
La implementación real 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 de WinRT, algunos métodos especiales, como Yield
, Rx observables y socket awaitables especiales que no afectan al GC tan duro . Las tareas son poderosas, pero no son las únicas esperables.
Nos viene a la mente una pequeña y pequeña diferencia insignificante: si el awaitable ya está completo, entonces el método async
realidad no regresa en ese punto; continúa sincrónicamente Así que es como pasar TaskContinuationOptions.ExecuteSynchronously
, pero sin los problemas relacionados con la pila.