2012-08-10 10 views
88

así me dijeron recientemente que la forma en que estaba usando mi .ContinueWith para las tareas no era la forma correcta de utilizarlos. Todavía tengo que encontrar pruebas de esto en Internet, así que les pregunto a ustedes y veo cuál es la respuesta. Aquí está un ejemplo de cómo uso .ContinueWith:prevTask.Wait() recomendado para ser utilizado con ContinueWith (de la biblioteca de tareas)?

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 esto es un ejemplo sencillo y va a correr muy rápido, pero sólo asumirá cada tarea hace alguna 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 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"); 
    }); 
} 
+2

No use StartNew http://blog.stephencleary.com/2013/08/startnew-is-dangerous.html –

Respuesta

113

Ehhh .... Creo que algunas de las respuestas actuales están perdiendo algo: lo que sucede con las excepciones?

La única razón por la que llamaría al 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 al Result en el caso de un Task<T> y también si accede manualmente a la propiedad Exception. Francamente, no me gustaría llamar al Wait o acceder al 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 con el antecedente 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: al especificar TaskContinuationOptions.NotOnFaulted en sus llamadas ContinueWith se evitaría que la lógica de continuación incluso se activara.

Tenga en cuenta que, si sus propias continuaciones no observan la excepción, la persona que está esperando completar este flujo de trabajo general será quien la observe. O bien están Wait ing en el Task upstream 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.

+2

Por fin alguien dé una respuesta correcta. @ Travyguy9 Lea esta respuesta @DrewMarsh y lea más acerca de 'TaskContinuationOptions' – Jasper

+0

Buena llamada. ¡Gracias! – Travyguy9

+2

Gran respuesta, estaba buscando _ "Tenga en cuenta que, si sus propias continuaciones no observan la excepción, la persona que está esperando que este flujo de trabajo general se complete será el que lo observe". _ Una pregunta sin embargo, cuando no se espera su tarea, ¿quién es el mozo predeterminado? (No se pudo encontrar la respuesta a esto) –

20

Usted está usando correctamente.

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

Fuente: Task.ContinueWith Method (Action as MSDN)

Tener que llamar prevTask.Wait() en todos los Task.ContinueWith invocación parece una forma extraña a repetir la lógica innecesaria - es decir, hacer algo para ser "Super Duper seguro", porque en realidad no entiende lo un cierto bit de código lo hace. Al igual que la comprobación de un nulo acaba de lanzar un ArgumentNullException donde habría sido arrojado de todos modos.

Así que no, quien te dijo eso es un error y probablemente no entiende por qué existe Task.ContinueWith.

5

Desde el MSDN en Task.Continuewith

El regresó tarea no será programado para su ejecución hasta que la tarea actual ha completado. Si no se cumplen los criterios especificados por el parámetro continuationOptions, la tarea de continuación ser cancelada en lugar de programado.

Creo que la manera correcta de hacerlo funciona en el primer ejemplo.

16

¿Quién te dijo eso?

Citando MSDN:

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

Además, ¿cuál sería el propósito de Continuar Con si no estaba a la espera de la tarea anterior para ser completado?

Incluso puede probar por ti 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"); 
    }); 
0

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

+0

Sí. Podemos evitar el método Wait(). Pero funciona solo con tareas de resultado, p. Tarea

+0

Downvoted porque no atiende la pregunta real. Agrega algún valor, pero debería ser un comentario. – Sinaesthetic

1

También puede ser que desee considerar el uso de Task.Run en lugar de Task.Factory.StartNew.

Stephen Cleary's blog post y Stephen Toub's post that he references explican las diferencias. También hay una discusión en this answer.

+3

Downvoted porque no aborda la pregunta real. Agrega algún valor, pero debería ser un comentario. – Sinaesthetic

0

Reitero lo que muchos ya han hablado, prevTask.Wait()es innecesario.

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

Cuestiones relacionadas