async + await == sync?

24

Tropecé con esta publicación que habla sobre hacer solicitudes web asíncronas.

Ahora, aparte de la simplicidad, si en el mundo real, todo lo que haces es hacer una solicitud asíncrona y esperarla en la siguiente línea, ¿no es lo mismo que hacer una llamada de sincronización en primer lugar?

Mrchief
fuente
55
No exactamente. Su código es sincrónico en el sentido de que no sucede nada hasta que obtenga un resultado. Sin embargo, debajo, probablemente renunció al hilo en el que estaba ejecutando hasta que regresó el método asíncrono, luego se le asignó otro hilo para continuar ejecutándose.
R0MANARMY
2
es pero con async puedes hacer otro async al mismo tiempo y luego esperar a los 2, con la sincronización esto no es posible
Ratchet freak
Aquí hay un artículo ( tomasp.net/blog/async-compilation-internals.aspx ) que discute algunos de los secretos de async en C #: es parte de una serie que cubre la programación asincrónica en C # y F #.
Paul
@ratchetfreak: Sí, no hace falta decir si estás haciendo varias llamadas.
Mrchief
@ R0MANARMY: Si su aplicación está haciendo otras cosas, entonces sí y async + aguarda lo habilita. ¡Akim lo dice mejor! Pero imagine que el código no está en el controlador button_click, o cualquier controlador de eventos de ese tipo. Si alguien copia ciegamente el código (asíncrono + líneas de espera), a cualquier método, puede dar lugar a una falsa impresión de que su código es asíncrono pero en efecto puede no serlo.
Mrchief

Respuestas:

32

No, async + await != syncdebido a la continuación.

Desde MSDN 'Programación asincrónica con asíncrono y espera (C # y Visual Basic)'

Los métodos asíncronos están destinados a ser operaciones sin bloqueo. Una expresión de espera en un método asíncrono no bloquea el hilo actual mientras se ejecuta la tarea esperada. En cambio, la expresión registra el resto del método como una continuación y devuelve el control al llamador del método asíncrono .

Por ejemplo, la ejecución asincrónica no bloqueará el subproceso de la interfaz de usuario y Some TextBox.Textse actualizará una vez que la descarga haya finalizado

private async void OnButtonClick()
{
   SomeTextBox.Text = await new WebClient().DownloadStringTaskAsync("http://stackoverflow.com/");
}
Akim
fuente
Muy bien dicho!
Mrchief
¿Podría explicar con más detalle? ¿Estás diciendo ... que sin esto ... no podrías interactuar con la interfaz de usuario ... ya que esto estaría en el hilo principal. Entonces, ¿esto significa que esto solo se aplica en un programa de tipo de aplicación destinado a la web donde la interacción es independiente del hilo del servidor web? Entonces, en pocas palabras, esto solo se vuelve importante, es decir, no se sincroniza * cuando su hilo principal es el hilo en ejecución. ¿No crearía esto un comportamiento inesperado, es decir, en una aplicación (1 subproceso principal) dos botones pulsados ​​... pero debería poder hacer clic en el 1 sin completar primero?
Seabizkit
¿Qué hay de Console.WriteLine(await GetStringOverNetwork());? ¿Qué sucede si necesita la salida de la invocación asincrónica? ¿Se bloqueará el programa en el primer acceso, incluso si el hilo podría continuar la ejecución?
Andrew
6

No, no es lo mismo.

Su asyncbloque de código está esperando que la awaitllamada regrese para continuar, sin embargo, el resto de su aplicación no está esperando y aún puede continuar de manera normal.

Por el contrario, una llamada síncrona haría que toda su aplicación o hilo espere hasta que el código termine de ejecutarse para continuar con cualquier otra cosa.

Rachel
fuente
¿No podría implementarse la llamada de sincronización como async + esperar?
Ratchet Freak
@ratchetfreak Creo que hay algunos gastos generales para configurar wait / async, así que no creo que quieras codificar toda tu aplicación con ella. Solo lo uso para ejecutar bloques de código potencialmente largos para que no bloquee mis aplicaciones. :)
Rachel
5

Permítanme aclarar cosas con respecto a async / wait.

Cuando se encuentra en espera, la máquina de estado subyacente permite que el control se devuelva de inmediato. Luego, cuando se completa la llamada esperada, la máquina de estado subyacente permite que la ejecución se reanude en la línea después de la llamada esperada.

Por lo tanto, el bloque asíncrono no está bloqueado ni está esperando que finalice la llamada esperada; El control se devuelve inmediatamente cuando se encuentra el comando de espera.

La máquina de estado subyacente es parte de la "magia" detrás del uso de async / wait que no se usa y se pierde.

Cedric Harris
fuente
2

Me topé con esto con la misma pregunta en mente, sin embargo, después de leer las respuestas, la pregunta parece persistir, confundida por las referencias a "magia bajo el capó".

De la programación asincrónica mencionada anteriormente :

  • La asyncpalabra clave convierte un método en un método asíncrono, que le permite utilizar la awaitpalabra clave en su cuerpo.
  • Cuando awaitse aplica la palabra clave, suspende el método de llamada y devuelve el control a la persona que llama hasta que se complete la tarea esperada.
  • awaitsolo se puede usar dentro de un asyncmétodo.

¿Se awaitbloquea el contexto que se encuentra ?

  • . Esa es esencialmente una barrera de sincronización local para mantener un estado conocido en el contexto de la ejecución; excepto que otros contextos, si los hay, no están unidos.

¿El resto de la aplicación se bloquea en el await?

  • Depende de cómo se escriba su solicitud. Si se trata de una serie de awaittareas ed dependientes iniciadas secuencialmente en el mismo contexto (ver: Intentando entender un comportamiento asíncrono / en espera )

    await asyncCall1();
    await asyncCall2();  // waits for asyncCall1() to complete

    de esta manera, cada uno awaitbloquearía el desove del siguiente.

    Por otro lado, las mismas tareas dependientes lanzadas en paralelo se ejecutarían en paralelo y el contexto solo se bloquearía en el resp. await:

    Task<int> t1 = asyncCall1();
    Task<string> t2 = asyncCall2();  // runs in parallel with asyncCall1()
    int val = await t1;
    string str = await t2;  // waits for asyncCall1() to complete

    En general, el awaitrendimiento se ejecuta en el contexto externo, desde donde se llama al contexto actual. Sin embargo, si el contexto externo en sí mismo espera la corriente, es como una secuencial awaiten el mismo contexto.

Entonces, para cosechar los asyncbeneficios, uno necesita diseñar la aplicación para ejecutar varios contextos paralelos (UI, cliente de datos, etc.), luego, awaiten un contexto, se ejecuta a otros contextos, para que toda la aplicación no se bloquee en un individuo await.

sobreinfligido
fuente