Threads erstellen - Task.Factory.StartNew vs new Thread ()

102

Ich lerne gerade etwas über die neuen Threading- und Parallel-Bibliotheken in .Net 4

In der Vergangenheit habe ich so einen neuen Thread erstellt (als Beispiel):

DataInThread = new Thread(new ThreadStart(ThreadProcedure));
DataInThread.IsBackground = true;
DataInThread.Start();

Jetzt kann ich tun:

Task t = Task.Factory.StartNew(() =>
{
   ThreadProcedure();
});

Was ist der Unterschied, wenn überhaupt?

Vielen Dank

Jon
quelle
1
Sie müssen sich ein wenig darüber ärgern, wie der Thread-Pool-Scheduler funktioniert. Es kann einen großen Unterschied machen, aber das hängt alles davon ab, was Sie tatsächlich im Thread tun.
Hans Passant

Antworten:

79

Es gibt einen großen Unterschied. Aufgaben werden auf dem ThreadPool geplant und können bei Bedarf sogar synchron ausgeführt werden.

Wenn Sie eine lange laufende Hintergrundarbeit haben, sollten Sie diese mithilfe der richtigen Task-Option angeben.

Sie sollten die Task Parallel Library der expliziten Thread-Behandlung vorziehen, da sie optimierter ist. Sie haben auch mehr Funktionen wie Fortsetzung.

Sanosdole
quelle
5
Nein, tut es nicht. Es werden nur Aufgaben gestartet. Dies könnte die Aufgabe in den Thread-Pool einreihen oder synchron ausführen. Bei der TPL geht es darum, Sie von der Verwaltung der Threads / Parallelität selbst zu befreien und das Beste für Ihre Plattform zu verwenden (wie die Verwendung von Kernen)
sanosdole
10
Es gibt die Option TaskCreationOptions.LongRunning, mit der immer ein anderer Thread erstellt wird. Der springende Punkt ist jedoch, warum Sie einen anderen Thread benötigen. Wenn Sie nur etwas parallel ausführen möchten (Main erledigt etw., Während Task ausgeführt wird), sollten Sie eine optimierte Bibliothek entscheiden lassen, wie Systemressourcen wie Threads verwendet werden, um dies auf die effizienteste Weise zu tun.
Sanosdole
3
Dieser MSDN-Artikel beschreibt, wie Aufgaben geplant werden. Es behandelt Longrunning & Inlining (synchrone Ausführung). msdn.microsoft.com/en-us/library/dd997402.aspx
sanosdole
2
@sming Der Punkt ist, dass Sie gleichzeitig verarbeiten möchten (ohne die Benutzeroberfläche zu blockieren) und nicht, dass Sie einen neuen Thread möchten. Der ThreadPool blockiert den UI-Thread nicht, verwaltet die Hintergrund-Threads jedoch wesentlich effizienter als Sie es manuell tun könnten, indem Sie Threads erstellen. Das ist die Veränderung im Denkprozess, die die TPL einführt. Denken Sie nicht an Threads, sondern an gleichzeitige Aufgaben.
Sanosdole
4
@sming Sorry, dieser Satz war etwas zu grob. Die synchrone Ausführung von Aufgaben wird als Inlining bezeichnet. Wenn Sie eine Aufgabe im Threadpool (Standardplaner) über den UI-Thread planen, tritt sie nicht auf. Dies tritt nur auf, wenn der Umgebungsplaner ('TaskScheduler.Current') mit dem Planer einer Aufgabe identisch ist, für die Sie '.Wait ()' aufrufen. Da '.Wait ()' blockiert, wird die Benutzeroberfläche trotzdem blockiert. Kurz: Rufen Sie nicht an und es wird nicht synchron ausgeführt.
Sanosdole
73

Die Aufgabe bietet Ihnen alle Vorteile der Aufgaben-API:

  • Fortsetzungen hinzufügen ( Task.ContinueWith)
  • Warten auf mehrere Aufgaben (entweder alle oder alle)
  • Fehler in der Aufgabe erfassen und später abfragen
  • Stornierung erfassen (und Sie können zunächst die Stornierung festlegen)
  • Möglicherweise mit einem Rückgabewert
  • Verwenden von Warten in C # 5
  • Bessere Kontrolle über die Zeitplanung (wenn es lange dauern wird, sagen Sie dies, wenn Sie die Aufgabe erstellen, damit der Aufgabenplaner dies berücksichtigen kann)

Beachten Sie, dass Sie in beiden Fällen Ihren Code mit Methodengruppenkonvertierungen etwas einfacher gestalten können:

DataInThread = new Thread(ThreadProcedure);
// Or...
Task t = Task.Factory.StartNew(ThreadProcedure);
Jon Skeet
quelle
8
+1. Ich möchte hinzufügen, dass dies Threadim Vergleich zu sehr niedrig ist Task(ich habe einen Blog-Beitrag , der ins Detail geht). Ich halte beim Grand Rapids DevDay einen Vortrag über "Aufgaben in der realen Welt verwenden" . Der Vortrag heißt "Thread is Dead", da dies nicht mehr erforderlich ist Thread(es sei denn, Sie implementieren a TaskScheduler).
Stephen Cleary
@StephenCleary, ich nehme an, Sie meinen, Threadist tot, wenn es darum geht, als Hintergrund-Thread verwendet zu werden?
Ebbe
1
@ebb: Nein, ich nehme die stärkere Position ein, die in meinem ersten Kommentar beschrieben wurde. Es gibt nichts , was man nicht eleganter und angemessener machen Threadkann (oder kann BackgroundWorker) . TaskTaskScheduler
Stephen Cleary
1
@StephenCleary, Wie würden Sie einen dedizierten Thread erstellen, ohne ihn zu verwenden Thread?
Ebbe
4
@ebb: "Dedicated Thread" ist mir nicht klar. Wenn Sie möchten Task, dass a auf einem bestimmten Thread ausgeführt wird, verwenden Sie einen geeigneten Thread, TaskSchedulerz AsyncContextThread. Dies ist jedoch normalerweise nicht erforderlich. die SynchronizationContext, ThreadPoolund ConcurrentExclusiveSchedulerPairDisponenten sind für die meisten Programme ausreichend.
Stephen Cleary
12

Im ersten Fall starten Sie einfach einen neuen Thread, während Sie im zweiten Fall in den Thread-Pool eintreten.

Der Thread-Pool- Job besteht darin, Threads freizugeben und zu recyceln. So können Sie vermeiden, dass jedes Mal, wenn wir einen neuen Thread erstellen müssen, einige Millisekunden verloren gehen.

Es gibt verschiedene Möglichkeiten, in den Thread-Pool einzutreten:

  • mit der TPL (Task Parallel Library) wie Sie
  • durch Aufrufen von ThreadPool.QueueUserWorkItem
  • durch Aufrufen von BeginInvoke für einen Delegaten
  • wenn Sie einen BackgroundWorker verwenden
alexandrekow
quelle
1

Ihr erster Codeblock weist CLR an, einen Thread (z. B. T) für Sie zu erstellen, der als Hintergrund ausgeführt werden kann (verwenden Sie Thread-Pool-Threads, wenn Sie T planen). Kurz gesagt, Sie fordern CLR ausdrücklich auf, einen Thread zu erstellen, damit Sie etwas tun können, und rufen die Start () -Methode für den Thread auf, um zu starten.

Ihr zweiter Codeblock macht dasselbe, delegiert jedoch (implizit Handover) die Verantwortung für das Erstellen eines Threads (Hintergrund - der wiederum im Thread-Pool ausgeführt wird) und des Startthreads über die StartNew-Methode in der Task Factory-Implementierung.

Dies ist ein schneller Unterschied zwischen bestimmten Codeblöcken. Trotzdem gibt es nur wenige detaillierte Unterschiede, die Sie googeln oder andere Antworten meiner Mitwirkenden sehen können.

s_nair
quelle