Ich habe Methode:
private static void Method()
{
Console.WriteLine("Method() started");
for (var i = 0; i < 20; i++)
{
Console.WriteLine("Method() Counter = " + i);
Thread.Sleep(500);
}
Console.WriteLine("Method() finished");
}
Und ich möchte diese Methode in einer neuen Aufgabe starten. Ich kann so eine neue Aufgabe starten
var task = Task.Factory.StartNew(new Action(Method));
oder dieses
var task = Task.Run(new Action(Method));
Aber gibt es einen Unterschied zwischen Task.Run()
und Task.Factory.StartNew()
. Beide verwenden ThreadPool und starten Method () unmittelbar nach dem Erstellen der Instanz der Task. Wann sollten wir die erste Variante verwenden und wann die zweite?
c#
multithreading
task-parallel-library
Sergiy Lichenko
quelle
quelle
StartNew
standardmäßig in Verwendungen, beiTaskScheduler.Current
denen es sich möglicherweise um den Thread-Pool, aber auch um den UI-Thread handelt.Antworten:
Die zweite Methode wurde
Task.Run
in einer späteren Version des .NET Frameworks (in .NET 4.5) eingeführt.Die erste Methode
Task.Factory.StartNew
bietet Ihnen jedoch die Möglichkeit, viele nützliche Dinge über den Thread zu definieren, den Sie erstellen möchten,Task.Run
ohne dies zu tun.Angenommen, Sie möchten einen lang laufenden Task-Thread erstellen. Wenn ein Thread des Thread-Pools für diese Aufgabe verwendet wird, kann dies als Missbrauch des Thread-Pools angesehen werden.
Eine Möglichkeit, dies zu vermeiden, besteht darin, die Aufgabe in einem separaten Thread auszuführen. Ein neu erstellter Thread , der dieser Aufgabe gewidmet ist und nach Abschluss Ihrer Aufgabe zerstört wird. Sie können dies nicht mit dem erreichen
Task.Run
, während Sie dies mit dem folgenden tun könnenTask.Factory.StartNew
:Wie hier angegeben :
quelle
that’s exactly equivalent to
nicht enthält.tha's exactly equivalent to
nicht enthält , außer wenn Sie diesen Kern teilen . Danke im Voraus. Es wäre schön, mit einem Kommentar zu Ihrem Code zu erklären. Danke :)TaskScheduler.Default
. Bitte schauen Sie hier referencesource.microsoft.com/#mscorlib/system/threading/Tasks/… .Das haben die Leute schon erwähnt
Ist äquivalent zu
Aber das hat niemand erwähnt
Ist äquivalent zu:
Wie Sie sehen können, unterscheiden sich zwei Parameter für
Task.Run
undTask.Factory.StartNew
:TaskCreationOptions
-Task.Run
Verwendet,TaskCreationOptions.DenyChildAttach
was bedeutet, dass untergeordnete Aufgaben nicht an die Eltern angehängt werden können. Beachten Sie Folgendes:Wenn wir anrufen
parentTask.Wait()
,childTask
wird nicht erwartet, obwohl wir es angegebenTaskCreationOptions.AttachedToParent
haben, liegt dies daran,TaskCreationOptions.DenyChildAttach
dass Kinder verbieten, sich daran zu binden. Wenn Sie den gleichen Code mitTask.Factory.StartNew
anstelle von ausführenTask.Run
,parentTask.Wait()
wird aufchildTask
weilTask.Factory.StartNew
verwendet gewartetTaskCreationOptions.None
TaskScheduler
-Task.Run
Verwendet,TaskScheduler.Default
was bedeutet, dass der Standard-Taskplaner (der Aufgaben im Thread-Pool ausführt) immer zum Ausführen von Aufgaben verwendet wird.Task.Factory.StartNew
Auf der anderen Seite verwendet,TaskScheduler.Current
was bedeutet, Scheduler des aktuellen Threads, es kann sein,TaskScheduler.Default
aber nicht immer. Tatsächlich ist es bei der EntwicklungWinforms
oder beiWPF
Anwendungen erforderlich, die Benutzeroberfläche aus dem aktuellen Thread zu aktualisieren. DazuTaskScheduler.FromCurrentSynchronizationContext()
verwendenTaskScheduler.FromCurrentSynchronizationContext()
die Benutzer den Taskplaner. Wenn Sie unbeabsichtigt eine andere Aufgabe mit langer Laufzeit innerhalb der Aufgabe erstellen, die den Planer verwendet hat, wird die Benutzeroberfläche eingefroren. Eine ausführlichere Erklärung hierzu finden Sie hierWenn Sie also keine verschachtelte untergeordnete Aufgabe verwenden und immer möchten, dass Ihre Aufgaben im Thread-Pool ausgeführt werden, ist es im Allgemeinen besser, sie zu verwenden
Task.Run
, es sei denn, Sie haben komplexere Szenarien.quelle
Siehe diesen Blog-Artikel , der den Unterschied beschreibt. Grundsätzlich tun:
Ist das gleiche wie:
quelle
Das
Task.Run
wurde in einer neueren .NET Framework-Version eingeführt und wird empfohlen .Das
Task.Factory.StartNew
hat mehr Möglichkeiten, dasTask.Run
ist eine Abkürzung:Und mit Kurzschrift meine ich eine technische Abkürzung :
quelle
Laut diesem Beitrag von Stephen Cleary ist Task.Factory.StartNew () gefährlich:
Hier sind die tatsächlichen Gründe:
Das bedeutet, dass es möglicherweise auf dem UI-Thread ausgeführt werden kann, wenn ein Vorgang abgeschlossen ist, und dass es aufgrund einer Fortsetzung zum UI-Thread zurückmarschiert, wie Stephen Cleary in seinem Beitrag ausführlicher erklärt.
In meinem Fall habe ich versucht, Aufgaben im Hintergrund auszuführen, wenn ein Datagrid für eine Ansicht geladen wurde, während gleichzeitig eine belebte Animation angezeigt wurde. Die belebte Animation wurde bei der Verwendung nicht angezeigt,
Task.Factory.StartNew()
aber die Animation wurde beim Umschalten ordnungsgemäß angezeigtTask.Run()
.Weitere Informationen finden Sie unter https://blog.stephencleary.com/2013/08/startnew-is-dangerous.html
quelle
Abgesehen von den Ähnlichkeiten, dh Task.Run () ist eine Abkürzung für Task.Factory.StartNew (), gibt es einen winzigen Unterschied zwischen ihrem Verhalten bei synchronisierten und asynchronen Delegaten.
Angenommen, es gibt zwei Methoden:
Betrachten Sie nun den folgenden Code.
Hier sind sowohl sync1 als auch sync2 vom Typ Task <int>
Bei asynchronen Methoden besteht jedoch ein Unterschied.
In diesem Szenario ist async1 vom Typ Task <int>, async2 jedoch vom Typ Task <Task> <int>
quelle
Task.Run
die Entpackungsfunktionalität derUnwrap
Methode integriert ist. Hier ist ein Blog-Beitrag, der die Gründe für diese Entscheidung erklärt.In meiner Anwendung, die zwei Dienste aufruft, habe ich sowohl Task.Run als auch Task.Factory.StartNew verglichen . Ich fand, dass in meinem Fall beide gut funktionieren. Der zweite ist jedoch schneller.
quelle