Was ist der Unterschied zwischen Aufgabe und Thread?

378

In C # 4.0 haben wir Taskim System.Threading.Tasks- Namespace. Was ist der wahre Unterschied zwischen Threadund Task. Ich habe ein Beispielprogramm (Hilfe von MSDN) durchgeführt, um selbst zu lernen

Parallel.Invoke 
Parallel.For 
Parallel.ForEach 

aber habe viele Zweifel, da die Idee nicht so klar ist.

Ich habe ursprünglich in Stackoverflow nach einer ähnlichen Art von Frage gesucht, aber möglicherweise konnte ich mit diesem Fragentitel nicht dieselbe bekommen. Wenn jemand weiß, dass dieselbe Art von Frage früher hier veröffentlicht wurde, geben Sie bitte den Verweis auf den Link an.

Hippietrail
quelle
8
Threads führen Aufgaben aus
pm100

Antworten:

314

Eine Aufgabe ist etwas, das Sie erledigen möchten.

Ein Thread ist einer der vielen möglichen Arbeiter, die diese Aufgabe ausführen.

In .NET 4.0-Begriffen repräsentiert eine Aufgabe eine asynchrone Operation. Threads werden verwendet, um diesen Vorgang abzuschließen, indem die Arbeit in Blöcke aufgeteilt und separaten Threads zugewiesen wird.

Mitch Wheat
quelle
Könnten Sie ein rudimentäres Beispiel für Threads liefern, die zur Ausführung einer Aufgabe arbeiten? Ich weiß nicht, ob die Threads Arbeiten ausführen, die unabhängig voneinander sind, oder ob sie eine Teamarbeit berechnen?
Pensum
Beide Szenarien sind möglich: In einer optimalen Situation arbeiten Threads unabhängig voneinander, ohne dass eine Synchronisierung mit anderen Threads erforderlich ist. In der Praxis werden Sperren verwendet, um Threads zu koordinieren.
Mitch Wheat
451

In der Informatik Taskist a eine Zukunft oder ein Versprechen . (Einige Leute verwenden diese beiden Begriffe synonym, andere verwenden sie unterschiedlich, niemand kann sich auf eine genaue Definition einigen .) Grundsätzlich ein Task<T>"Versprechen", Ihnen einen zurückzugeben T, aber momentan nicht, Schatz, ich bin ein bisschen beschäftigt, warum nicht kommst du später zurück

A Threadist ein Weg, dieses Versprechen zu erfüllen. Aber nicht jeder Taskbraucht einen brandneuen Thread. (Tatsächlich ist das Erstellen eines Threads oft unerwünscht, da dies viel teurer ist als die Wiederverwendung eines vorhandenen Threads aus dem Threadpool. Mehr dazu gleich.) Wenn der Wert, auf den Sie warten, aus dem Dateisystem stammt oder a Datenbank oder das Netzwerk, dann muss kein Thread herumstehen und auf die Daten warten, wenn andere Anforderungen bearbeitet werden können. Stattdessen Taskregistrieren sie möglicherweise einen Rückruf, um die Werte zu erhalten, wenn sie bereit sind.

Insbesondere Tasksagt das nicht aus , warum es so lange dauert, bis der Wert zurückgegeben wird. Es kann sein, dass das Berechnen lange dauert, oder dass das Abrufen lange dauert. Nur im ersteren Fall würden Sie a verwenden, um a Threadauszuführen Task. (In .NET sind Threads verdammt teuer, daher möchten Sie sie im Allgemeinen so weit wie möglich vermeiden und sie wirklich nur verwenden, wenn Sie mehrere umfangreiche Berechnungen auf mehreren CPUs ausführen möchten. In Windows wiegt ein Thread beispielsweise 12 KiByte ( Ich denke), unter Linux wiegt ein Thread nur 4 KiByte, in Erlang / BEAM sogar nur 400 Byte. In .NET ist es 1 MiByte!)

Jörg W Mittag
quelle
29
Interessanterweise gab es in den frühen Vorschauversionen von TPL (Task Parallel Library) Task and Future <T>. Future <T> wurde dann in Task <T> umbenannt. :)
Lee Campbell
23
Wie haben Sie 1 MB für .NET berechnet?
Dvallejo
5
@DanVallejo: Diese Nummer wurde in einem Interview mit dem TPL-Designteam erwähnt. Ich kann dir nicht sagen, wer es gesagt hat oder welches Interview es war, das habe ich mir vor Jahren angesehen.
Jörg W Mittag
9
@RIPUNJAYTRIPATHI Sicher, aber es muss kein anderer Thread sein, es könnte der Thread sein, der die Arbeit überhaupt angefordert hat.
Chris Pitman
7
.NET verwendet nur Windows-Threads unter Windows, daher ist die Größe gleich - standardmäßig normalerweise 1 MB virtueller Speicher für beide. Der physische Speicher wird nach Bedarf in Seitenblöcken (normalerweise 64 KB) verwendet, genau wie bei nativem Code. Die minimale Größe des Thread-Stacks hängt vom Betriebssystem ab - beispielsweise 256 kiB für Vista. Unter x86 Linux beträgt der Standard normalerweise 2 MiB - wiederum in Blöcken mit Seitengröße. (Vereinfachung) Erlang verwendet nur einen Systemthread pro Prozess Task. Diese 400 Bytes beziehen sich auf etwas Ähnliches wie .NETs .
Luaan
39

Faden

Das Bare-Metal-Ding, das Sie wahrscheinlich nicht benötigen, können Sie wahrscheinlich eine LongRunningAufgabe verwenden und die Vorteile der TPL - Task Parallel Library nutzen, die in .NET Framework 4 (Februar 2002) und höher (auch .NET) enthalten ist Ader).

Aufgaben

Abstraktion über den Fäden. Es verwendet den Thread-Pool (es sei denn, Sie geben die Aufgabe als LongRunningOperation an. In diesem Fall wird unter der Haube ein neuer Thread für Sie erstellt).

Thread-Pool

Wie der Name schon sagt: ein Pool von Threads. Verarbeitet das .NET Framework eine begrenzte Anzahl von Threads für Sie? Warum? Da das Öffnen von 100 Threads zur Ausführung teurer CPU-Operationen auf einem Prozessor mit nur 8 Kernen definitiv keine gute Idee ist. Das Framework verwaltet diesen Pool für Sie, verwendet die Threads wieder (nicht bei jedem Vorgang erstellen / beenden) und führt einige davon parallel aus, sodass Ihre CPU nicht brennt.

OK, aber wann soll jeder verwendet werden?

Im Lebenslauf: Verwenden Sie immer Aufgaben.

Aufgabe ist eine Abstraktion, daher ist sie viel einfacher zu verwenden. Ich rate Ihnen, immer zu versuchen, Aufgaben zu verwenden. Wenn Sie auf ein Problem stoßen, bei dem Sie einen Thread selbst bearbeiten müssen (wahrscheinlich 1% der Zeit), verwenden Sie Threads.

ABER sei dir bewusst, dass:

  • E / A-gebunden : Verwenden Sie für E / A-gebundene Vorgänge (Datenbankaufrufe, Lese- / Schreibdateien, API-Aufrufe usw.) die Verwendung normaler Aufgaben, verwenden Sie LongRunningAufgaben ( oder Threads, falls erforderlich ). Denn die Verwendung von Aufgaben würde Sie zu einem Thread-Pool führen, in dem einige Threads beschäftigt sind und viele andere Aufgaben darauf warten, dass der Pool an die Reihe kommt.
  • CPU-gebunden : Verwenden Sie für CPU-gebundene Vorgänge einfach die normalen Aufgaben (die intern den Thread-Pool verwenden) und freuen Sie sich.
Fabriciorissetto
quelle
leichte Korrektur, ein Thread ist kein "Bare-Metal-Ding". Es wird vom Betriebssystem implementiert. Die meisten Implementierungen basieren auf Funktionen der CPU und des CS, werden jedoch nicht von der Hardware implementiert.
Tomer W
7

Sie können Taskangeben, was Sie tun möchten, und dies dann Taskmit einem anhängen Thread. Das Taskwürde also in diesem neu erstellten Threadund nicht im GUI-Thread ausgeführt.

Verwenden Sie Taskmit dem TaskFactory.StartNew(Action action). Hier führen Sie einen Delegaten aus. Wenn Sie also keinen Thread verwenden, wird dieser im selben Thread (GUI-Thread) ausgeführt. Wenn Sie einen Thread erwähnen, können Sie diesen Taskin einem anderen Thread ausführen . Dies ist eine unnötige Arbeit, da Sie den Delegaten direkt ausführen oder diesen Delegaten an einen Thread anhängen und diesen Delegaten in diesem Thread ausführen können. Also benutze es nicht. es ist nur unnötig. Wenn Sie Ihre Software optimieren möchten, ist dies ein guter Kandidat, der entfernt werden sollte.

** Bitte beachten Sie, dass das ein Actionist delegate.

Gryphes
quelle
6

Zusätzlich zu den oben genannten Punkten wäre es gut zu wissen, dass:

  1. Eine Aufgabe ist standardmäßig eine Hintergrundaufgabe. Sie können keine Vordergrundaufgabe haben. Andererseits kann ein Thread Hintergrund oder Vordergrund sein (Verwenden Sie die IsBackground-Eigenschaft, um das Verhalten zu ändern).
  2. Im Thread-Pool erstellte Aufgaben recyceln die Threads, wodurch Ressourcen gespart werden. In den meisten Fällen sollten Aufgaben Ihre Standardauswahl sein.
  3. Wenn die Operationen schnell sind, ist es viel besser, eine Aufgabe anstelle eines Threads zu verwenden. Für lange Betriebsvorgänge bieten Aufgaben keine großen Vorteile gegenüber Threads.
user2492339
quelle
4

Normalerweise Taskinteragiere ich mit Winforms und einfachen Hintergrundarbeitern, damit die Benutzeroberfläche nicht einfriert. hier ein Beispiel, wenn ich es vorzieheTask

private async void buttonDownload_Click(object sender, EventArgs e)
{
    buttonDownload.Enabled = false;
    await Task.Run(() => {
        using (var client = new WebClient())
        {
            client.DownloadFile("http://example.com/file.mpeg", "file.mpeg");
        }
    })
    buttonDownload.Enabled = true;
}

VS

private void buttonDownload_Click(object sender, EventArgs e)
{
    buttonDownload.Enabled = false;
    Thread t = new Thread(() =>
    {
        using (var client = new WebClient())
        {
            client.DownloadFile("http://example.com/file.mpeg", "file.mpeg");
        }
        this.Invoke((MethodInvoker)delegate()
        {
            buttonDownload.Enabled = true;
        });
    });
    t.IsBackground = true;
    t.Start();
}

Der Unterschied besteht darin, dass Sie keinen MethodInvokerkürzeren Code verwenden müssen.

ewwink
quelle
4

Die Aufgabe ist wie eine Operation, die Sie ausführen möchten. Thread hilft dabei, diese Operation über mehrere Prozessknoten zu verwalten. Task ist eine einfache Option, da Threading zu einer komplexen Codeverwaltung führen kann.
Ich werde vorschlagen, immer von MSDN (Best in World) Task zu lesen

Faden

Saurabh
quelle
3

Eine Aufgabe kann als bequeme und einfache Möglichkeit angesehen werden, etwas asynchron und parallel auszuführen.

Normalerweise ist eine Aufgabe alles, was Sie brauchen. Ich kann mich nicht erinnern, ob ich jemals einen Thread für etwas anderes als zum Experimentieren verwendet habe.

Sie können mit einem Thread (mit viel Aufwand) dasselbe erreichen wie mit einer Aufgabe.

Faden

int result = 0;
Thread thread = new System.Threading.Thread(() => { 
    result = 1; 
});
thread.Start();
thread.Join();
Console.WriteLine(result); //is 1

Aufgabe

int result = await Task.Run(() => {
    return 1; 
});
Console.WriteLine(result); //is 1

Eine Aufgabe verwendet standardmäßig den Threadpool, wodurch Ressourcen gespart werden, da das Erstellen von Threads teuer sein kann. Sie können eine Aufgabe als eine übergeordnete Abstraktion für Threads anzeigen.

Wie in diesem Artikel ausgeführt , bietet die Task über den Thread die folgenden leistungsstarken Funktionen.

  • Die Aufgaben sind auf die Nutzung von Multicores-Prozessoren abgestimmt.

  • Wenn das System mehrere Aufgaben hat, verwendet es den CLR-Thread-Pool intern und hat daher nicht den Overhead, der mit dem Erstellen eines dedizierten Threads mithilfe des Threads verbunden ist. Reduzieren Sie auch die Kontextwechselzeit zwischen mehreren Threads.

  • Task kann ein Ergebnis zurückgeben. Es gibt keinen direkten Mechanismus, um das Ergebnis vom Thread zurückzugeben.
  • Warten Sie auf eine Reihe von Aufgaben ohne Signalisierungskonstrukt.

  • Wir können Aufgaben miteinander verketten, um sie nacheinander auszuführen.

  • Richten Sie eine Eltern-Kind-Beziehung ein, wenn eine Aufgabe von einer anderen Aufgabe aus gestartet wird.

  • Die Ausnahme für untergeordnete Aufgaben kann an übergeordnete Aufgaben weitergegeben werden.

  • Stornierung der Aufgabenunterstützung durch Verwendung von Stornierungs-Token.

  • Die asynchrone Implementierung ist mit den Schlüsselwörtern 'async' und 'await' einfach durchzuführen.

CharithJ
quelle