continuewith await c# task-parallel-library

c# - await - ¿Se recomienda usar prevTask.Wait() para continuar con ContinueWith(desde la biblioteca de Tareas)?



await continuewith (7)

Así que me dijeron hace poco que la forma en que estaba usando mi .ContinueWith para tareas no era la forma adecuada de usarlas. Todavía tengo que encontrar pruebas de esto en Internet, así que les pregunto a ustedes y veo cuál es la respuesta. Aquí hay un ejemplo de cómo uso .ContinueWith:

public Task DoSomething() { return Task.Factory.StartNew(() => { Console.WriteLine("Step 1"); }) .ContinueWith((prevTask) => { Console.WriteLine("Step 2"); }) .ContinueWith((prevTask) => { Console.WriteLine("Step 3"); }); }

Ahora sé que este es un ejemplo simple y funcionará muy rápido, pero asuma que cada tarea realiza una operación más larga. Entonces, lo que me dijeron es que en .ContinueWith, necesitas decir prevTask.Wait (); de lo contrario, podría hacer el trabajo antes de que termine la tarea anterior. ¿Es eso posible? Supuse que mi segunda y tercera tarea solo se ejecutaría una vez que finalizara su tarea anterior.

Lo que me dijeron cómo escribir el código:

public Task DoSomething() { return Task.Factory.StartNew(() => { Console.WriteLine("Step 1"); }) .ContinueWith((prevTask) => { prevTask.Wait(); Console.WriteLine("Step 2"); }) .ContinueWith((prevTask) => { prevTask.Wait(); Console.WriteLine("Step 3"); }); }


¿Quién te dijo eso?

Citando MSDN :

Crea una continuación que se ejecuta de forma asíncrona cuando finaliza la tarea objetivo.

Además, ¿cuál sería el propósito de Continuar con si no estaba esperando que se complete la tarea anterior?

Incluso puede probarlo usted mismo:

Task.Factory.StartNew(() => { Console.WriteLine("Step 1"); Thread.Sleep(2000); }) .ContinueWith((prevTask) => { Console.WriteLine("I waited step 1 to be completed!"); }) .ContinueWith((prevTask) => { Console.WriteLine("Step 3"); });


Al acceder a Task.Result , en realidad está haciendo una lógica similar a task.wait


Desde MSDN en Task.Continuewith

La tarea devuelta no se programará para su ejecución hasta que la tarea actual se haya completado. Si no se cumplen los criterios especificados mediante el parámetro continuationOptions, la tarea de continuación se cancelará en lugar de programarse.

Creo que la manera correcta en la que esperas que funcione en el primer ejemplo.


Ehhh ... Creo que a algunas de las respuestas actuales les falta algo: ¿qué ocurre con las excepciones?

La única razón por la que llamaría Wait en una continuación sería observar una posible excepción del antecedente en la continuación misma. La misma observación ocurriría si accediera a Result en el caso de una Task<T> y también si accede manualmente a la propiedad de Exception . Francamente, no llamaría a Wait o accedería a Result porque si hay una excepción pagará el precio de volver a subirla, lo cual es una sobrecarga innecesaria. En su lugar, puede verificar la propiedad IsFaulted fuera de la Task . Alternativamente, puede crear flujos de trabajo bifurcados encadenando varias continuaciones de hermanos que solo se activan según el éxito o el fracaso con TaskContinuationOptions.OnlyOnRanToCompletion y TaskContinuationOptions.OnlyOnFaulted .

Ahora, no es necesario observar la excepción del antecedente en la continuación, pero es posible que no desee que su flujo de trabajo avance si, por ejemplo, falló el "Paso 1". En ese caso: especificar TaskContinuationOptions.NotOnFaulted para sus llamadas ContinueWith evitaría que la lógica de continuación incluso se active.

Tenga en cuenta que, si sus propias continuaciones no observan la excepción, la persona que está esperando que se complete este flujo de trabajo general será quien la observe. O bien están Wait la Task sentido ascendente o han añadido su propia continuación para saber cuándo se completó. Si es el último, su continuación necesitaría usar la lógica de observación antes mencionada.


Lo estás usando correctamente

Crea una continuación que se ejecuta de forma asíncrona cuando finaliza la tarea objetivo.

Fuente: Tarea . Continuar con método (acción como MSDN)

Tener que llamar a prevTask.Wait() en cada Task.ContinueWith invocación parece una forma extraña de repetir lógica innecesaria, es decir, hacer algo para estar "súper seguro" porque en realidad no entiendes lo que hace un cierto código. Como buscar un nulo solo para arrojar una ArgumentNullException donde habría sido arrojada de todos modos.

Entonces, no, quien te dijo que está mal y probablemente no entienda por qué Task.ContinueWith existe.



Voy a reiterar lo que muchos ya han hablado, prevTask.Wait() es innecesario .

Para obtener más ejemplos, puede ir a Chaining Tasks usando Continuation Tasks , otro enlace de Microsoft con buenos ejemplos.