Concernant l'utilisation de Task.Start (), Task.Run () et Task.Factory.StartNew ()

143

Je viens de voir 3 routines concernant l'utilisation de TPL qui font le même travail; voici le code:

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();                  
}

Je ne comprends pas pourquoi MS donne 3 façons différentes pour exécuter des travaux en TPL parce qu'ils travaillent tous les mêmes: Task.Start(), Task.Run()et Task.Factory.StartNew().

Dites - moi, sont Task.Start(), Task.Run()et Task.Factory.StartNew()tous utilisés dans le même but ou ont-ils une signification différente?

Quand doit-on utiliser Task.Start(), quand doit-on utiliser Task.Run()et quand doit-on utiliser Task.Factory.StartNew()?

S'il vous plaît, aidez-moi à comprendre leur utilisation réelle selon le scénario en détail avec des exemples, merci.

Mou
la source
il y a un vieil article expliquant cela ici et ici pour le plus récentTask.Run - peut-être que cela répondra à votre question;)
Carsten
Voici un exemple où Task.Startest réellement utile.
noseratio
Double
Michael Freidgeim

Réponses:

171

Task.Runest un raccourci pour Task.Factory.StartNewavec des arguments sûrs spécifiques:

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

Il a été ajouté dans .Net 4.5 pour aider à l'utilisation de plus en plus fréquente asyncet au déchargement du travail vers le ThreadPool.

Task.Factory.StartNew(ajouté avec TPL dans .Net 4.0) est beaucoup plus robuste. Vous ne devriez l'utiliser que si cela Task.Runne suffit pas, par exemple lorsque vous souhaitez l'utiliser TaskCreationOptions.LongRunning(bien que ce ne soit pas nécessaire lorsque le délégué est asynchrone. Plus à ce sujet sur mon blog: LongRunning Is Useless For Task.Run With async-await ). Plus sur le sujet Task.Factory.StartNewdans Task.Run vs Task.Factory.StartNew

Ne créez jamais un " Taskand call" à Start()moins que vous ne trouviez une très bonne raison de le faire. Il ne doit être utilisé que si vous avez une partie qui doit créer des tâches mais pas de planification et une autre partie qui planifie sans créer. Ce n'est presque jamais une solution appropriée et pourrait être dangereuse. Plus d'informations dans "Task.Factory.StartNew" vs "nouvelle tâche (...). Démarrer"

En conclusion, utilisez principalement Task.Run, utilisez Task.Factory.StartNewsi vous devez et ne l'utilisez jamais Start.

i3arnon
la source
5
u dit "Ne créez jamais une tâche et appelez Start ()", redirigez-moi vers n'importe quelle bonne rédaction qui montrera que cela peut être causé par Task.Start (). J'ai besoin de détails parce que tu dis pour l'éviter. Merci pour votre réponse.
Mou
1
@Mou Task.Starta sa place pour hériter des types principalement.
Yuval Itzchakov
1
@Mou C'est inefficace car il nécessite une synchronisation pour s'assurer qu'il n'est appelé qu'une seule fois. Les autres options ne le font pas.
i3arnon
2
@Mou Vous devriez probablement lire le post qui explique ce problème blogs.msdn.com/b/pfxteam/archive/2010/06/13/10024153.aspx
i3arnon
2

Réponse courte :

Si vous n'utilisez pas de tâches enfants imbriquées et que vous souhaitez toujours que vos tâches soient exécutées sur le pool de threads, il est préférable de l'utiliser Task.Run.

Longue réponse:

Task.Runet les Task.Factory.StartNewdeux fournissent un support pour la création et la planification d'objets de tâche afin que nous n'ayons pas besoin de créer un Taskappel etStart()

Task.Run(action);

Est équivalent à:

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

Et

Task.Factory.StartNew(action);

Est équivalent à:

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

Task.Runutilise TaskCreationOptions.DenyChildAttachce qui signifie que les tâches des enfants ne peuvent pas être attachées au parent et qu'il utilise TaskScheduler.Defaultce qui signifie que celui qui exécute les tâches sur le pool de threads sera toujours utilisé pour exécuter des tâches.

Task.Factory.StartNewutilise TaskScheduler.Currentce qui signifie le planificateur du thread actuel, cela peut être TaskScheduler.Defaultmais pas toujours.

Ali Bayat
la source