Con respecto al uso de Task.Start (), Task.Run () y Task.Factory.StartNew ()

143

Acabo de ver 3 rutinas con respecto al uso de TPL que hacen el mismo trabajo; Aquí está el código:

public static void Main()
{
    Thread.CurrentThread.Name = "Main";

    // Create a task and supply a user delegate by using a lambda expression. 
    Task taskA = new Task( () => Console.WriteLine("Hello from taskA."));
    // Start the task.
    taskA.Start();

    // Output a message from the calling thread.
    Console.WriteLine("Hello from thread '{0}'.", 
                  Thread.CurrentThread.Name);
    taskA.Wait();
}

public static void Main()
{
    Thread.CurrentThread.Name = "Main";

    // Define and run the task.
    Task taskA = Task.Run( () => Console.WriteLine("Hello from taskA."));

    // Output a message from the calling thread.
    Console.WriteLine("Hello from thread '{0}'.", 
                      Thread.CurrentThread.Name);
    taskA.Wait();
}

public static void Main()
{
    Thread.CurrentThread.Name = "Main";

    // Better: Create and start the task in one operation. 
    Task taskA = Task.Factory.StartNew(() => Console.WriteLine("Hello from taskA."));

    // Output a message from the calling thread.
    Console.WriteLine("Hello from thread '{0}'.", 
                    Thread.CurrentThread.Name);

    taskA.Wait();                  
}

Simplemente no entiendo por qué MS da 3 métodos diferentes para ejecutar trabajos en TPL, ya que todo el trabajo de la misma: Task.Start(), Task.Run()y Task.Factory.StartNew().

Dime, están Task.Start(), Task.Run()y Task.Factory.StartNew()todos utilizados para el mismo propósito o tienen un significado diferente?

¿Cuándo se debe usar Task.Start(), cuándo se debe usar Task.Run()y cuándo se debe usar Task.Factory.StartNew()?

Ayúdenme a comprender su uso real según el escenario en gran detalle con ejemplos, gracias.

Mou
fuente
hay un artículo antiguo que explica que aquí y aquí para los más nuevosTask.Run , tal vez esto responderá a su pregunta;)
Carsten
Aquí hay un ejemplo de dónde Task.Startes realmente útil.
noseratio

Respuestas:

171

Task.Runes una abreviatura Task.Factory.StartNewcon argumentos seguros específicos:

Task.Factory.StartNew(
    action, 
    CancellationToken.None, 
    TaskCreationOptions.DenyChildAttach, 
    TaskScheduler.Default);

Se agregó en .Net 4.5 para ayudar con el uso cada vez más frecuente asyncy la descarga de trabajo en el ThreadPool.

Task.Factory.StartNew(agregado con TPL en .Net 4.0) es mucho más robusto. Solo debe usarlo si Task.Runno es suficiente, por ejemplo, cuando quiere usarlo TaskCreationOptions.LongRunning(aunque es innecesario cuando el delegado es asíncrono. Más sobre eso en mi blog: LongRunning es inútil para la tarea. Ejecutar con async-wait ). Más sobre Task.Factory.StartNewen Task.Run vs Task.Factory.StartNew

Nunca cree una Taskllamada a Start()menos que encuentre una muy buena razón para hacerlo. Solo debe usarse si tiene alguna parte que necesita crear tareas pero no programarlas y otra parte que programa sin crear. Esa casi nunca es una solución adecuada y podría ser peligrosa. Más en "Task.Factory.StartNew" frente a "new Task (...). Start"

En conclusión, use principalmente Task.Run, use Task.Factory.StartNewsi debe y nunca use Start.

i3arnon
fuente
55
dijiste "Nunca crees una tarea y llames a Start ()" redirígeme a cualquier buena redacción que muestre las causas que puede causar Task.Start (). Necesito detalles porque estás diciendo para evitarlo. gracias por responder.
Mou
1
@Mou Task.Starttiene su lugar para heredar tipos principalmente.
Yuval Itzchakov
1
@Mou Es ineficiente ya que requiere sincronización para asegurarse de que solo se llame una vez. Las otras opciones no.
i3arnon
2
@Mou Probablemente deberías leer la publicación que explica este problema blogs.msdn.com/b/pfxteam/archive/2010/06/13/10024153.aspx
i3arnon
2

Respuesta corta :

Si no está utilizando tareas infantiles anidadas y siempre desea que sus tareas se ejecuten en Thread Pool , es mejor usarlas Task.Run.

Respuesta larga:

Task.Runy Task.Factory.StartNewambos brindan soporte para crear y programar objetos de Tarea para que no necesitemos crear una TaskllamadaStart()

Task.Run(action);

Es equivalente a:

Task.Factory.StartNew(action, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);

Y

Task.Factory.StartNew(action);

Es equivalente a:

Task.Factory.StartNew(action, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Current);

Task.Runusa lo TaskCreationOptions.DenyChildAttachque significa que las tareas de los niños no se pueden adjuntar a los padres y usa lo TaskScheduler.Defaultque significa que la que ejecuta tareas en Thread Pool siempre se usará para ejecutar tareas.

Task.Factory.StartNewutiliza lo TaskScheduler.Currentque significa planificador del subproceso actual, puede ser TaskScheduler.Defaultpero no siempre.

Ali Bayat
fuente