In Bezug auf die Verwendung von Task.Start (), Task.Run () und Task.Factory.StartNew ()

142

Ich habe gerade 3 Routinen bezüglich der TPL-Verwendung gesehen, die den gleichen Job machen. Hier ist der 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();                  
}

Ich verstehe einfach nicht , warum MS 3 verschiedene Möglichkeiten gibt Arbeitsplätze in TPL laufen , weil sie alle Arbeiten gleich: Task.Start(), Task.Run()und Task.Factory.StartNew().

Sag mir, sind Task.Start(), Task.Run()und Task.Factory.StartNew()alle für den gleichen Zweck verwendet oder haben sie andere Bedeutung?

Wann sollte man verwenden Task.Start(), wann sollte man verwenden Task.Run()und wann sollte man verwenden Task.Factory.StartNew()?

Bitte helfen Sie mir, ihre tatsächliche Verwendung gemäß dem Szenario anhand von Beispielen detailliert zu verstehen, danke.

Mou
quelle
Es gibt einen alten Artikel, der erklärt, dass hier und hier für die neuerenTask.Run - vielleicht wird dies Ihre Frage beantworten;)
Carsten
Hier ist ein Beispiel dafür, wo dies Task.Starttatsächlich nützlich ist.
Noseratio

Antworten:

171

Task.Runist eine Abkürzung für Task.Factory.StartNewmit bestimmten sicheren Argumenten:

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

Es wurde in .Net 4.5 hinzugefügt, um die immer häufiger werdende Nutzung asyncund Verlagerung von Arbeiten an die .Net 4.5 zu erleichtern ThreadPool.

Task.Factory.StartNew(hinzugefügt mit TPL in .Net 4.0) ist viel robuster. Sie sollten es nur verwenden, wenn Task.Runes nicht ausreicht, z. B. wenn Sie es verwenden möchten TaskCreationOptions.LongRunning(obwohl es nicht erforderlich ist, wenn der Delegat asynchron ist . Mehr dazu in meinem Blog: LongRunning ist für Aufgaben nutzlos. Mit asynchronem Warten ausführen ). Mehr dazu Task.Factory.StartNewin Task.Run vs Task.Factory.StartNew

Erstellen Sie niemals ein Taskund rufen Start()Sie an, es sei denn, Sie finden einen sehr guten Grund dafür. Es sollte nur verwendet werden, wenn Sie einen Teil haben, der Aufgaben erstellen, aber nicht planen muss, und einen anderen Teil, der ohne Erstellen geplant wird. Das ist fast nie eine angemessene Lösung und könnte gefährlich sein. Mehr in "Task.Factory.StartNew" vs "Neue Aufgabe (...). Start"

Abschließend, meistens verwenden Task.Run, verwenden, Task.Factory.StartNewwenn Sie müssen und nie verwenden Start.

i3arnon
quelle
5
Sie sagten "Erstellen Sie niemals eine Aufgabe und rufen Sie Start () auf". Leiten Sie mich zu einem guten Bericht weiter, der zeigt, dass dies möglicherweise durch Task.Start () verursacht wird. Ich brauche Details, weil du sagst, um es zu vermeiden. danke für die Antwort.
Mou
ru über diesen Link sprechen blogs.msdn.com/b/pfxteam/archive/2010/06/13/10024153.aspx ??
Mou
1
@Mou Task.Starthat seinen Platz für das Erben von Typen meistens.
Yuval Itzchakov
1
@Mou Es ist ineffizient, da eine Synchronisierung erforderlich ist, um sicherzustellen, dass es nur einmal aufgerufen wird. Die anderen Optionen nicht.
i3arnon
2
@Mou Sie sollten wahrscheinlich den Beitrag lesen, der dieses Problem erklärt blogs.msdn.com/b/pfxteam/archive/2010/06/13/10024153.aspx
i3arnon
2

Kurze Antwort :

Wenn Sie keine verschachtelten untergeordneten Aufgaben verwenden und immer möchten, dass Ihre Aufgaben im Thread-Pool ausgeführt werden , ist es besser, sie zu verwenden Task.Run.

Lange Antwort:

Task.Runund Task.Factory.StartNewbeide bieten Unterstützung für das Erstellen und Planen von Aufgabenobjekten, sodass wir kein a Taskund keinen Aufruf erstellen müssenStart()

Task.Run(action);

Ist äquivalent zu:

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

Und

Task.Factory.StartNew(action);

Ist äquivalent zu:

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

Task.Runverwendet, TaskCreationOptions.DenyChildAttachwas bedeutet, dass untergeordnete Aufgaben nicht an das übergeordnete Element angehängt werden können, und verwendet, TaskScheduler.Defaultwas bedeutet, dass diejenige, die Aufgaben im Thread-Pool ausführt, immer zum Ausführen von Aufgaben verwendet wird.

Task.Factory.StartNewverwendet, TaskScheduler.Currentwas bedeutet, Scheduler des aktuellen Threads, es kann sein, TaskScheduler.Defaultaber nicht immer.

Ali Bayat
quelle