¿Cuál es la diferencia entre Task.Start / Wait y Async / Await?

Puede que me esté perdiendo algo, pero cuál es la diferencia entre hacer:

public void MyMethod() { Task t = Task.Factory.StartNew(DoSomethingThatTakesTime); t.Wait(); UpdateLabelToSayItsComplete(); } public async void MyMethod() { var result = Task.Factory.StartNew(DoSomethingThatTakesTime); await result; UpdateLabelToSayItsComplete(); } private void DoSomethingThatTakesTime() { Thread.Sleep(10000); } 

Puedo estar olvidando algo

Usted está.

¿ Task.Wait es la diferencia entre hacer Task.Wait y await task ?

Usted ordena su almuerzo del camarero en el restaurante. Un momento después de dar su pedido, un amigo entra, se sienta a su lado y comienza una conversación. Ahora tienes dos opciones. Puede ignorar a su amigo hasta que la tarea esté completa; puede esperar hasta que llegue su sopa y no hacer nada más mientras espera. O puede responder a su amigo, y cuando su amigo deje de hablar, el camarero le traerá su sopa.

Task.Wait bloques hasta que la tarea se complete; ignoras a tu amigo hasta que la tarea se complete. await sigue procesando mensajes en la cola de mensajes, y cuando la tarea se completa, pone en cola un mensaje que dice “continuar donde lo dejó después de que lo aguarde”. Hablas con tu amigo, y cuando hay un descanso en la conversación llega la sopa.

Para demostrar la respuesta de Eric aquí hay un código:

 public void ButtonClick(object sender, EventArgs e) { Task t = new Task.Factory.StartNew(DoSomethingThatTakesTime); t.Wait(); //If you press Button2 now you won't see anything in the console //until this task is complete and then the label will be updated! UpdateLabelToSayItsComplete(); } public async void ButtonClick(object sender, EventArgs e) { var result = Task.Factory.StartNew(DoSomethingThatTakesTime); await result; //If you press Button2 now you will see stuff in the console and //when the long method returns it will update the label! UpdateLabelToSayItsComplete(); } public void Button_2_Click(object sender, EventArgs e) { Console.WriteLine("Button 2 Clicked"); } private void DoSomethingThatTakesTime() { Thread.Sleep(10000); } 

Este ejemplo demuestra la diferencia muy claramente. Con async / await, el hilo de llamada no se bloqueará y continuará ejecutándose.

 static void Main(string[] args) { WriteOutput("Program Begin"); // DoAsTask(); DoAsAsync(); WriteOutput("Program End"); Console.ReadLine(); } static void DoAsTask() { WriteOutput("1 - Starting"); var t = Task.Factory.StartNew(DoSomethingThatTakesTime); WriteOutput("2 - Task started"); t.Wait(); WriteOutput("3 - Task completed with result: " + t.Result); } static async Task DoAsAsync() { WriteOutput("1 - Starting"); var t = Task.Factory.StartNew(DoSomethingThatTakesTime); WriteOutput("2 - Task started"); var result = await t; WriteOutput("3 - Task completed with result: " + result); } static int DoSomethingThatTakesTime() { WriteOutput("A - Started something"); Thread.Sleep(1000); WriteOutput("B - Completed something"); return 123; } static void WriteOutput(string message) { Console.WriteLine("[{0}] {1}", Thread.CurrentThread.ManagedThreadId, message); } 

Salida de DoAsTask:

 [1] Progtwig Comenzar
 [1] 1 - Comenzar
 [1] 2 - Tarea iniciada
 [3] A - Comenzó algo
 [3] B - Completó algo
 [1] 3 - Tarea completada con resultado: 123
 [1] Final del progtwig

Salida DoAsAsync:

 [1] Progtwig Comenzar
 [1] 1 - Comenzar
 [1] 2 - Tarea iniciada
 [3] A - Comenzó algo
 [1] Final del progtwig
 [3] B - Completó algo
 [3] 3 - Tarea completada con el resultado: 123

Actualización: ejemplo mejorado al mostrar la ID del hilo en la salida.

En este ejemplo, no mucho, prácticamente. Si está esperando una tarea que devuelve un hilo diferente (como una llamada WCF) o renuncia al control del sistema operativo (como File IO), aguarde utilizará menos recursos del sistema al no bloquear un hilo.

Wait (), hará que se ejecute el código potencialmente asíncrono de manera sincronizada. espera no lo hará.

Por ejemplo, tiene una aplicación web asp.net. UserA calls / getUser / 1 endpoint. El grupo de aplicaciones asp.net seleccionará un hilo del grupo de subprocesos (Thread1) y este hilo realizará una llamada http. Si lo hace, Wait (), este subproceso se bloqueará hasta que se resuelva la llamada http. Mientras espera, si UserB calls / getUser / 2, el grupo de aplicaciones deberá enviar otro hilo (Thread2) para realizar una llamada http nuevamente. Acabas de crear (Bueno, en realidad, se ha obtenido del grupo de aplicaciones) otro hilo sin ninguna razón, porque no puedes usar Thread1, fue bloqueado por Wait ().

Si usa await en Thread1, SyncContext administrará la sincronización entre Thread1 y la llamada http. Simplemente, notificará una vez que se realice la llamada http. Mientras tanto, si UserB llama / getUser / 2, entonces, usarás Thread1 nuevamente para hacer una llamada http, porque se liberó una vez que se agotó. Entonces otra solicitud puede usarlo, incluso más. Una vez que se realiza la llamada http (usuario1 o usuario2), Thread1 puede obtener el resultado y regresar a la persona que llama (cliente). Thread1 se usó para múltiples tareas.

En el ejemplo anterior, puede usar “TaskCreationOptions.HideScheduler” y modificar en gran medida el método “DoAsTask”. El método en sí no es asíncrono, como ocurre con “DoAsAsync” porque devuelve un valor de “Tarea” y está marcado como “async”, haciendo varias combinaciones, así es como me da exactamente lo mismo que usar “async / await” :

 static Task DoAsTask() { WriteOutput("1 - Starting"); var t = Task.Factory.StartNew(DoSomethingThatTakesTime, TaskCreationOptions.HideScheduler); //<-- HideScheduler do the magic TaskCompletionSource tsc = new TaskCompletionSource(); t.ContinueWith(tsk => tsc.TrySetResult(tsk.Result)); //<-- Set the result to the created Task WriteOutput("2 - Task started"); tsc.Task.ContinueWith(tsk => WriteOutput("3 - Task completed with result: " + tsk.Result)); //<-- Complete the Task return tsc.Task; }