whenall understanding method httpresponsemessage ejemplo create await async c# async-await task

understanding - task whenall c#



Mezclando async/await con resultado (2)

Escenario uno: estás sentado en tu escritorio. Hay una bandeja de entrada. Esta vacio. De repente, llega un papel a su bandeja de entrada describiendo una tarea. Te pones de pie y comienzas a correr haciendo la tarea. Pero, ¿cuál es la tarea? Dice que haga lo siguiente:

  • Cambie la pizarra para decir "en ejecución" - OK, usted hace eso.
  • Configure su despertador por una hora más tarde. OK, haz eso.
  • Cree una nueva hoja de papel que diga "cuando suena la alarma, escriba la palabra HECHO en la pizarra". Ponlo en tu bandeja de entrada. Haces eso.
  • No haga nada más hasta que la palabra HECHO esté escrita en la pizarra.
  • Regrese a su escritorio y espere a que la siguiente tarea llegue a la bandeja de entrada.

Este flujo de trabajo le impide realizar el trabajo porque los dos últimos pasos están en el orden incorrecto.

Escenario dos: estás sentado en tu escritorio. Hay una bandeja de entrada. Esta vacio. De repente, llega un papel a su bandeja de entrada describiendo una tarea. Te pones de pie y comienzas a correr haciendo la tarea. Pero, ¿cuál es la tarea? Dice que haga lo siguiente:

  • Cambie la pizarra para decir "en ejecución" - OK, usted hace eso.
  • Dale esta otra hoja de papel a Debbie en el próximo cubículo. OK, haz eso.
  • No haga nada hasta que alguien le diga que la subtarea está HECHO.
  • Cuando eso suceda, escriba la palabra HECHO en su pizarra.
  • Regresa a tu escritorio.

¿Qué dice la hoja de papel que le diste a Debbie? Dice:

  • Configure su despertador por una hora más tarde. OK, ella hace eso.
  • Cuando suene la alarma, coloque un papel en su bandeja de entrada y dígale a Middas que ha terminado.

Este flujo de trabajo sigue siendo terrible en el sentido de que (1) usted está sentado sin hacer nada mientras espera que suene la alarma de Debbie, y (2) está perdiendo el tiempo de dos trabajadores cuando podía hacer que un solo trabajador hiciera todo el trabajo . Los trabajadores son caros.

Pero este flujo de trabajo no le impide trabajar eventualmente . No se empantana porque no está esperando un trabajo que usted mismo va a hacer en el futuro , está esperando que alguien más haga el trabajo.

(Noto que esta no es una analogía exacta de lo que está sucediendo en su programa, pero está lo suficientemente cerca como para transmitir la idea).

Permítanme comenzar esta pregunta con algunas cosas:

  1. He leído varias preguntas sobre SO que dicen que no debes hacer esto (como Cómo mezclar de manera segura la sincronización y el código asincrónico )
  2. He leído Async / Await - Las mejores prácticas en la programación asincrónica, una vez más diciendo que no deberías hacer esto

Entonces sé que esta no es una mejor práctica, y no necesito que nadie me lo diga. Esta es más una pregunta de "por qué funciona esto".

Con eso fuera del camino, aquí está mi pregunta:

He escrito una pequeña aplicación GUI que tiene 2 botones y una etiqueta de estado. Uno de los botones reproducirá el problema de interbloqueo con sincronización y asincronización el 100% del tiempo. El otro botón llama al mismo método async pero está envuelto en una Tarea, esta funciona. Sé que esta no es una buena práctica de codificación, pero quiero entender por qué no tiene el mismo problema de interbloqueo. Aquí está el código:

public partial class Form1 : Form { public Form1() { InitializeComponent(); } private async Task<string> DelayAsync() { await Task.Delay(1000); return "Done"; } private void buttonDeadlock_Click(object sender, EventArgs e) { labelStatus.Text = "Status: Running"; // causes a deadlock because of mixing sync and async code var result = DelayAsync().Result; // never gets here labelStatus.Text = "Status: " + result; } private void buttonWorking_Click(object sender, EventArgs e) { labelStatus.Text = "Status: Running"; string result = null; // still technically mixes sync and async, but works, why? result = Task.Run(async () => { return await DelayAsync(); }).Result; labelStatus.Text = "Status: " + result; } }


Funciona porque el código asincrónico buttonWorking_Click ( DelayAsync así como el lambda async pasado a Task.Run ) no tiene un SynchronizationContext actual, mientras que el buttonDeadlock_Click async code ( DelayAsync ) sí lo hace. Puede observar la diferencia ejecutando en el depurador y viendo SynchronizationContext.Current .

Explico los detalles detrás del escenario de interbloqueo en la publicación de mi blog Do not Block on Async Code .