Wann wird der Thread-Pool in C # verwendet? [geschlossen]


127

Ich habe versucht, Multithread-Programmierung in C # zu lernen, und bin verwirrt darüber, wann es am besten ist, einen Thread-Pool zu verwenden oder meine eigenen Threads zu erstellen. In einem Buch wird empfohlen, einen Thread-Pool nur für kleine Aufgaben zu verwenden (was auch immer das bedeutet), aber ich kann anscheinend keine wirklichen Richtlinien finden. Welche Überlegungen berücksichtigen Sie bei dieser Programmierentscheidung?

Antworten:


47

Wenn Sie viele logische Aufgaben haben, die eine ständige Verarbeitung erfordern, und diese parallel ausgeführt werden sollen, verwenden Sie den Pool + Scheduler.

Wenn Sie Ihre E / A-bezogenen Aufgaben gleichzeitig ausführen müssen, z. B. das Herunterladen von Daten von Remoteservern oder den Festplattenzugriff, dies jedoch alle paar Minuten tun müssen, erstellen Sie Ihre eigenen Threads und beenden Sie sie, sobald Sie fertig sind.

Bearbeiten: In Bezug auf einige Überlegungen verwende ich Thread-Pools für Datenbankzugriff, Physik / Simulation, KI (Spiele) und für Skriptaufgaben, die auf virtuellen Maschinen ausgeführt werden, die viele benutzerdefinierte Aufgaben verarbeiten.

Normalerweise besteht ein Pool aus 2 Threads pro Prozessor (heutzutage also wahrscheinlich 4). Sie können jedoch die Anzahl der gewünschten Threads festlegen, wenn Sie wissen, wie viele Sie benötigen.

Bearbeiten: Der Grund für das Erstellen eigener Threads liegt in Kontextänderungen (in diesem Fall müssen Threads zusammen mit ihrem Speicher in den Prozess ein- und ausgeblendet werden). Wenn Sie nutzlose Kontextänderungen haben, z. B. wenn Sie Ihre Threads nicht verwenden, können Sie die Leistung Ihres Programms leicht halbieren, wenn Sie sie nur herumliegen lassen (sagen wir, Sie haben 3 schlafende Threads und 2 aktive Threads). Wenn diese Download-Threads nur warten, verbrauchen sie Tonnen von CPU und kühlen den Cache für Ihre echte Anwendung ab


2
Ok, aber können Sie erklären, warum Sie so vorgehen? Was ist beispielsweise der Nachteil der Verwendung des Thread-Pools zum Herunterladen von Remoteservern oder zum Ausführen von Festplatten-E / A?

8
Wenn ein Thread auf ein Synchronisationsobjekt wartet (Ereignis, Semaphor, Mutex usw.), verbraucht der Thread keine CPU.
Brannon

7
Wie Brannon sagte, ist ein verbreiteter Mythos, dass die Erstellung mehrerer Threads die Leistung beeinträchtigt. Tatsächlich verbrauchen nicht verwendete Threads nur sehr wenige Ressourcen. Kontextwechsel treten erst bei Servern mit sehr hoher Nachfrage auf (in diesem Fall finden Sie eine Alternative unter E / A-Abschlussports).
FDCastel

12
Beeinträchtigen inaktive Threads die Leistung? Es kommt darauf an, wie sie warten. Wenn sie gut geschrieben sind und auf ein Synchronisationsobjekt warten, sollten sie keine CPU-Ressourcen verbrauchen. Wenn Sie in einer Schleife warten, die regelmäßig aktiviert wird, um die Ergebnisse zu überprüfen, wird die CPU verschwendet. Wie immer kommt es auf eine gute Codierung an.
Bill

2
Inaktive verwaltete Threads verbrauchen Speicher für ihren Stapel. Standardmäßig beträgt 1 MiB pro Thread. Es ist also besser, wenn alle Threads funktionieren.
Vadym Stetsiak

48

Ich würde vorschlagen, dass Sie aus den gleichen Gründen wie jede andere Sprache einen Thread-Pool in C # verwenden.

Verwenden Sie einen Thread-Pool, wenn Sie die Anzahl der ausgeführten Threads begrenzen oder den Aufwand für das Erstellen und Zerstören dieser Threads nicht erhöhen möchten.

Bei kleinen Aufgaben bedeutet das Buch, das Sie lesen, Aufgaben mit kurzer Lebensdauer. Wenn es zehn Sekunden dauert, um einen Thread zu erstellen, der nur eine Sekunde lang ausgeführt wird, sollten Sie an dieser Stelle Pools verwenden (ignorieren Sie meine tatsächlichen Zahlen, es ist das Verhältnis, das zählt).

Andernfalls verbringen Sie den größten Teil Ihrer Zeit damit, Threads zu erstellen und zu zerstören, anstatt nur die Arbeit zu erledigen, für die sie vorgesehen sind.


28

Hier ist eine schöne Zusammenfassung des Thread-Pools in .Net: http://blogs.msdn.com/pedram/archive/2007/08/05/dedicated-thread-or-a-threadpool-thread.aspx

Der Beitrag enthält auch einige Punkte, wann Sie den Thread-Pool nicht verwenden und stattdessen Ihren eigenen Thread starten sollten.


8
-1 für den Link. Ich bin sicher, dass es ein guter Link ist, aber ich erwarte, dass SO autark ist.
Jon Davis

26
@ stimulpy77 - das ist dann die falsche Erwartung. SO kann niemals autark sein, da es weder die ultimative Autorität für alle Fragen ist, noch alle detaillierten Informationen zu jedem Thema in jeder SO-Antwort, die dieses Thema berührt, dupliziert werden können (und sollten). (und ich glaube nicht, dass Sie genug Ruf haben, um jede einzelne Antwort von Jon Skeet allein mit einem ausgehenden Link herunterzustimmen, geschweige denn alle Antworten aller SO-Benutzer mit ausgehenden Links :-))
Franci Penov

2
Vielleicht war ich zu prägnant, vielleicht sollte ich das klarstellen. Ich bin nicht gegen Links. Ich bin gegen Antworten, die nur einen Link enthalten. Ich denke nicht, dass das eine Antwort ist. Wenn nun eine kurze Zusammenfassung der Antwort veröffentlicht worden wäre, um zusammenzufassen, wie der verlinkte Inhalt angewendet wird, wäre dies akzeptabel. Außerdem bin ich hierher gekommen, um nach einer Antwort auf dasselbe Problem zu suchen, und diese Antwort hat mich irritiert, weil es ein weiterer Link war, auf den ich klicken musste, um eine Vorstellung davon zu haben, was er in Bezug auf das spezifische Problem sagen könnte. Wie bezieht sich Jon Skeet darauf? Und warum sollte es mich interessieren?
Jon Davis

8
"Sie sind zwei Jahre nach der Veröffentlichung zu diesem Beitrag gekommen, und alles, was ich hier kopiert habe, ist möglicherweise inzwischen veraltet." So könnte ein Link sein. Wenn Sie beim Posten eines Links eine kurze, aber vollständige Zusammenfassung veröffentlichen, wissen Sie nie, ob ein Link veraltet oder tot ist.
Jon Davis

2
Ich bin nicht mit Stimpy einverstanden: weder die Idee von Posts, die aufgrund von Unmöglichkeit Unmengen an Informationen enthalten, noch jemanden darüber anzurufen. Ich würde sagen, es ist wahrscheinlicher, dass ein Link nicht mehr funktionsfähig ist, als dass Inhalte veraltet / vermieden werden. Mehr Inhalt ist also schön, wenn es der Anlass erlaubt. Wir sind alle (meistens) Freiwillige, also sei dankbar für das, was du bekommst - danke Franci :)
zanlok

14

Ich empfehle dringend, dieses kostenlose E-Book zu lesen: Threading in C # von Joseph Albahari

Lesen Sie zumindest den Abschnitt "Erste Schritte". Das E-Book bietet eine großartige Einführung und enthält auch eine Fülle erweiterter Threading-Informationen.

Zu wissen, ob der Thread-Pool verwendet werden soll oder nicht, ist nur der Anfang. Als Nächstes müssen Sie bestimmen, welche Methode zum Eingeben des Thread-Pools Ihren Anforderungen am besten entspricht:

  • Task Parallel Library (.NET Framework 4.0)
  • ThreadPool.QueueUserWorkItem
  • Asynchrone Delegaten
  • BackgroundWorker

Dieses E-Book erklärt dies alles und gibt Ratschläge, wann Sie sie verwenden müssen, anstatt einen eigenen Thread zu erstellen.


8

Der Thread-Pool wurde entwickelt, um die Kontextumschaltung zwischen Ihren Threads zu reduzieren. Stellen Sie sich einen Prozess vor, in dem mehrere Komponenten ausgeführt werden. Jede dieser Komponenten kann Arbeitsthreads erstellen. Je mehr Threads sich in Ihrem Prozess befinden, desto mehr Zeit wird beim Kontextwechsel verschwendet.

Wenn nun jede dieser Komponenten Elemente in den Thread-Pool einreihen würde, wäre der Aufwand für die Kontextumschaltung wesentlich geringer.

Der Thread-Pool wurde entwickelt, um die Arbeit auf Ihren CPUs (oder CPU-Kernen) zu maximieren. Aus diesem Grund dreht der Thread-Pool standardmäßig mehrere Threads pro Prozessor.

In einigen Situationen möchten Sie den Thread-Pool nicht verwenden. Wenn Sie auf E / A oder auf ein Ereignis usw. warten, binden Sie diesen Thread-Pool-Thread zusammen und er kann von niemand anderem verwendet werden. Die gleiche Idee gilt für Aufgaben mit langer Laufzeit, obwohl das, was eine Aufgabe mit langer Laufzeit ausmacht, subjektiv ist.

Pax Diablo macht auch einen guten Punkt. Das Spinnen von Threads ist nicht kostenlos. Es braucht Zeit und sie verbrauchen zusätzlichen Speicher für ihren Stapelspeicher. Der Thread-Pool verwendet Threads erneut, um diese Kosten amortisieren zu können.

Hinweis: Sie haben nach der Verwendung eines Thread-Pool-Threads zum Herunterladen von Daten oder zum Ausführen von Festplatten-E / A gefragt. Sie sollten hierfür keinen Thread-Pool-Thread verwenden (aus den oben genannten Gründen). Verwenden Sie stattdessen asynchrone E / A (auch bekannt als BeginXX- und EndXX-Methoden). Für einen FileStreamwäre das BeginReadund EndRead. Für einen HttpWebRequestwäre das BeginGetResponseund EndGetResponse. Sie sind komplizierter zu verwenden, aber sie sind der richtige Weg, um Multithread-E / A durchzuführen.


1
ThreadPool ist eine clevere Automatisierung. "Wenn die Warteschlange länger als eine halbe Sekunde stationär bleibt, werden weitere Threads erstellt - einer alle halbe Sekunde - bis zur Kapazität des Thread-Pools" ( albahari.com/threading/#_Optimizing_the_Thread_Pool ). Auch fast asynchrone Operationen mit BeginXXX-EndXXX werden über ThreadPool verwendet. Daher ist es normal, ThreadPool zum Herunterladen von Daten zu verwenden, und dies wird häufig implizit verwendet.
Artru

6

Achten Sie auf den .NET-Thread-Pool für Vorgänge, die möglicherweise einen signifikanten, variablen oder unbekannten Teil ihrer Verarbeitung blockieren, da dieser anfällig für Thread-Hunger ist. Erwägen Sie die Verwendung der parallelen .NET-Erweiterungen, die eine gute Anzahl logischer Abstraktionen über Thread-Operationen bereitstellen. Sie enthalten auch einen neuen Scheduler, der eine Verbesserung von ThreadPool darstellen sollte. Siehe hier


2
Wir haben das auf die harte Tour entdeckt! ASP.Net verwendet den Threadpool, der angezeigt wird, und daher konnten wir ihn nicht so aggressiv verwenden, wie wir möchten.
Noocyte

3

Ein Grund, den Thread-Pool nur für kleine Aufgaben zu verwenden, besteht darin, dass nur eine begrenzte Anzahl von Thread-Pool-Threads vorhanden ist. Wenn einer für eine lange Zeit verwendet wird, wird verhindert, dass dieser Thread von anderem Code verwendet wird. Wenn dies häufig vorkommt, kann der Thread-Pool aufgebraucht sein.

Die Verwendung des Thread-Pools kann subtile Auswirkungen haben. Einige .NET-Timer verwenden Thread-Pool-Threads und werden beispielsweise nicht ausgelöst.


2

Wenn Sie eine Hintergrundaufgabe haben, die lange anhält, beispielsweise für die gesamte Lebensdauer Ihrer Anwendung, ist es sinnvoll, einen eigenen Thread zu erstellen. Wenn Sie kurze Jobs haben, die in einem Thread ausgeführt werden müssen, verwenden Sie Thread-Pooling.

In einer Anwendung, in der Sie viele Threads erstellen, wird der Aufwand für das Erstellen der Threads erheblich. Durch die Verwendung des Thread-Pools werden die Threads einmal erstellt und wiederverwendet, wodurch der Aufwand für die Thread-Erstellung vermieden wird.

In einer Anwendung, an der ich gearbeitet habe, hat der Wechsel von der Erstellung von Threads zur Verwendung des Thread-Pools für die kurzlebigen Threads den Durchsatz der Anwendung erheblich verbessert.


Bitte klären Sie, ob Sie "einen Thread-Pool" oder "den Thread-Pool" meinen. Dies sind sehr unterschiedliche Dinge (zumindest in der MS CLR).
bzlm

2

Um die höchste Leistung bei gleichzeitig ausgeführten Einheiten zu erzielen, schreiben Sie Ihren eigenen Thread-Pool, in dem beim Start ein Pool von Thread-Objekten erstellt wird, und blockieren Sie (früher angehalten), bis ein Kontext ausgeführt wird (ein Objekt mit einer von implementierten Standardschnittstelle) dein Code).

So viele Artikel über Aufgaben vs. Threads vs. .NET ThreadPool bieten Ihnen nicht wirklich das, was Sie benötigen, um eine Entscheidung für die Leistung zu treffen. Aber wenn Sie sie vergleichen, gewinnen Threads und insbesondere ein Pool von Threads. Sie sind am besten auf die CPUs verteilt und starten schneller.

Was diskutiert werden sollte, ist die Tatsache, dass die Hauptausführungseinheit von Windows (einschließlich Windows 10) ein Thread ist und der Aufwand für das Umschalten des Betriebssystemkontexts normalerweise vernachlässigbar ist. Einfach ausgedrückt, ich konnte für viele dieser Artikel keine überzeugenden Beweise finden, unabhängig davon, ob der Artikel eine höhere Leistung durch Einsparen von Kontextwechsel oder eine bessere CPU-Auslastung beansprucht.

Nun zu ein bisschen Realismus:

Die meisten von uns brauchen keine deterministische Anwendung, und die meisten von uns haben keinen harten Hintergrund mit Threads, was beispielsweise häufig mit der Entwicklung eines Betriebssystems einhergeht. Was ich oben geschrieben habe, ist nichts für Anfänger.

Am wichtigsten ist es also zu diskutieren, was einfach zu programmieren ist.

Wenn Sie Ihren eigenen Thread-Pool erstellen, müssen Sie ein wenig schreiben, da Sie sich mit der Verfolgung des Ausführungsstatus, der Simulation des Suspendierens und Fortsetzens und dem Abbrechen der Ausführung befassen müssen - auch in einer anwendungsweiten Ausführung Herunterfahren. Möglicherweise müssen Sie sich auch Gedanken darüber machen, ob Sie Ihren Pool dynamisch vergrößern möchten und welche Kapazitätsbeschränkungen Ihr Pool haben wird. Ich kann ein solches Framework in einer Stunde schreiben, aber das liegt daran, dass ich es so oft gemacht habe.

Der einfachste Weg, eine Ausführungseinheit zu schreiben, ist möglicherweise die Verwendung einer Aufgabe. Das Schöne an einer Aufgabe ist, dass Sie eine erstellen und in Ihrem Code inline starten können (obwohl Vorsicht geboten sein kann). Sie können ein Stornierungs-Token übergeben, um es zu bearbeiten, wenn Sie die Aufgabe abbrechen möchten. Außerdem wird der Versprechungsansatz zum Verketten von Ereignissen verwendet, und Sie können einen bestimmten Werttyp zurückgeben. Darüber hinaus gibt es mit Async und Warten mehr Optionen und Ihr Code wird portabler.

Im Wesentlichen ist es wichtig, die Vor- und Nachteile von Tasks vs. Threads vs. .NET ThreadPool zu verstehen. Wenn ich hohe Leistung benötige, verwende ich Threads und bevorzuge die Verwendung meines eigenen Pools.

Eine einfache Möglichkeit zum Vergleichen besteht darin, 512 Threads, 512 Tasks und 512 ThreadPool-Threads zu starten. Am Anfang von Threads tritt eine Verzögerung auf (daher sollte ein Thread-Pool geschrieben werden), aber alle 512 Threads werden in wenigen Sekunden ausgeführt, während der Start von Tasks- und .NET ThreadPool-Threads bis zu einigen Minuten dauert.

Nachfolgend finden Sie die Ergebnisse eines solchen Tests (i5 Quad Core mit 16 GB RAM), bei dem alle 30 Sekunden ausgeführt werden. Der ausgeführte Code führt eine einfache Datei-E / A auf einem SSD-Laufwerk aus.

Testergebnisse


1
Zu Ihrer Information, ich habe vergessen zu erwähnen, dass Aufgaben und .NET-Threads in .NET simuliert werden und die Verwaltung in .NET und nicht im Betriebssystem ausgeführt wird. Letzteres ist bei der Verwaltung gleichzeitiger Ausführungen wesentlich effizienter. Ich verwende Aufgaben für viele Dinge, aber ich verwende einen Betriebssystem-Thread für eine hohe Ausführungsleistung. MS behauptet, Aufgaben und .NET-Threads seien besser, aber sie dienen im Allgemeinen dazu, die Parallelität zwischen .NET-Apps auszugleichen. Eine Server-App ist jedoch am besten geeignet, wenn das Betriebssystem die Parallelität handhabt.

Würde gerne die Implementierung Ihres benutzerdefinierten Threadpools sehen. Schön zu schreiben!
Francis

Ich verstehe Ihre Testergebnisse nicht. Was bedeutet das "Units Ran"? Sie vergleichen 34 Takes mit 512 Threads? Würden Sie das bitte erklären?
Elmue

Unit ist nur eine Methode zur gleichzeitigen Ausführung in einem Task-, Thread- oder .NET ThreadPool-Arbeitsthread. In meinem Test wird die Start- / Ausführungsleistung verglichen. Jeder Test hat 30 Sekunden Zeit, um 512 Threads von Grund auf neu zu erstellen, 512 Aufgaben, 512 ThreadPool-Arbeitsthreads oder einen Pool von 512 gestarteten Threads fortzusetzen, die auf die Ausführung eines Kontexts warten. Die Tasks- und ThreadPool-Worker-Threads werden langsam hochgefahren, sodass 30 Sekunden nicht ausreichen, um sie alle hochzufahren. Wenn jedoch die Anzahl der ThreadPool-Min-Worker-Threads zuerst auf 512 festgelegt wird, werden sowohl Tasks- als auch ThreadPool-Worker-Threads fast so schnell wie 512-Threads von Grund auf neu gestartet.


1

Thread-Pools eignen sich hervorragend, wenn Sie mehr Aufgaben als verfügbare Threads verarbeiten müssen.

Sie können alle Aufgaben zu einem Thread-Pool hinzufügen und die maximale Anzahl von Threads angeben, die zu einem bestimmten Zeitpunkt ausgeführt werden können.

Schauen Sie sich diese Seite auf MSDN an: http://msdn.microsoft.com/en-us/library/3dasc8as(VS.80).aspx


Ok, ich denke, das hängt mit meiner anderen Frage zusammen. Woher wissen Sie, wie viele verfügbare Threads Sie zu einem bestimmten Zeitpunkt haben?

Nun, es ist schwer zu sagen. Sie müssen Leistungstests durchführen. Nach einem Punkt, an dem Sie mehr Threads hinzufügen, erhalten Sie keine höhere Geschwindigkeit. Finden Sie heraus, wie viele Prozessoren sich auf der Maschine befinden. Dies ist ein guter Ausgangspunkt. Wenn sich die Verarbeitungsgeschwindigkeit nicht verbessert, fügen Sie von dort aus keine weiteren Threads hinzu.
Lajos

1

Verwenden Sie immer einen Thread-Pool, wenn Sie können, und arbeiten Sie auf der höchstmöglichen Abstraktionsebene. Thread-Pools verbergen das Erstellen und Zerstören von Threads für Sie. Dies ist normalerweise eine gute Sache!


1

Meistens können Sie den Pool verwenden, da Sie den teuren Prozess zum Erstellen des Threads vermeiden.

In einigen Szenarien möchten Sie jedoch möglicherweise einen Thread erstellen. Zum Beispiel, wenn Sie nicht der einzige sind, der den Thread-Pool verwendet, und der von Ihnen erstellte Thread eine lange Lebensdauer hat (um den Verbrauch gemeinsam genutzter Ressourcen zu vermeiden) oder wenn Sie beispielsweise die Stapelgröße des Threads steuern möchten.


1

Vergessen Sie nicht, den Hintergrundarbeiter zu untersuchen.

Ich finde für viele Situationen, es gibt mir genau das, was ich will, ohne das schwere Heben.

Prost.


Wenn es sich um eine einfache App handelt, die weiterhin ausgeführt wird und Sie eine andere Aufgabe zu erledigen haben, ist es sehr einfach, diesen Code auszuführen. Sie haben jedoch keine Links angegeben: Spezifikation und Tutorial
Zanlok

0

Normalerweise benutze ich den Threadpool immer dann, wenn ich etwas in einem anderen Thread tun muss, und es ist mir egal, wann er ausgeführt wird oder endet. So etwas wie das Protokollieren oder vielleicht sogar das Herunterladen einer Datei im Hintergrund (obwohl es bessere Möglichkeiten gibt, dies asynchron zu tun). Ich benutze meinen eigenen Thread, wenn ich mehr Kontrolle brauche. Ich habe auch festgestellt, dass die Verwendung einer Threadsafe-Warteschlange (hacke deine eigene) zum Speichern von "Befehlsobjekten" gut ist, wenn ich mehrere Befehle habe, an denen ich in> 1 Thread arbeiten muss. Sie können also eine XML-Datei aufteilen und jedes Element in eine Warteschlange stellen. Anschließend arbeiten mehrere Threads an der Verarbeitung dieser Elemente. Ich habe vor langer Zeit eine solche Warteschlange in uni (VB.net!) Geschrieben, dass ich zu C # konvertiert habe. Ich habe es ohne besonderen Grund unten aufgeführt (dieser Code kann einige Fehler enthalten).

using System.Collections.Generic;
using System.Threading;

namespace ThreadSafeQueue {
    public class ThreadSafeQueue<T> {
        private Queue<T> _queue;

        public ThreadSafeQueue() {
            _queue = new Queue<T>();
        }

        public void EnqueueSafe(T item) {
            lock ( this ) {
                _queue.Enqueue(item);
                if ( _queue.Count >= 1 )
                    Monitor.Pulse(this);
            }
        }

        public T DequeueSafe() {
            lock ( this ) {
                while ( _queue.Count <= 0 )
                    Monitor.Wait(this);

                return this.DeEnqueueUnblock();

            }
        }

        private T DeEnqueueUnblock() {
            return _queue.Dequeue();
        }
    }
}

Einige Probleme bei diesem Ansatz: - Aufrufe von DequeueSafe () warten, bis ein Element EnqueuedSafe () ist. Verwenden Sie eine der Überladungen von Monitor.Wait (), um ein Zeitlimit anzugeben. - Das Sperren entspricht nicht den Best Practices, sondern erstellt ein schreibgeschütztes Objektfeld. - Obwohl Monitor.Pulse () leichtgewichtig ist, ist es effizienter, es aufzurufen, wenn die Warteschlange nur 1 Element enthält. - DeEnqueueUnblock () sollte vorzugsweise die Warteschlange überprüfen. Anzahl> 0. (erforderlich, wenn Monitor.PulseAll oder Wartezeitüberschreitungen verwendet werden)
Craig Nicholson

0

Ich wollte einen Thread-Pool, um die Arbeit mit möglichst geringer Latenz auf die Kerne zu verteilen, und das musste mit anderen Anwendungen nicht gut funktionieren. Ich stellte fest, dass die Leistung des .NET-Threadpools nicht so gut war, wie sie sein könnte. Ich wusste, dass ich einen Thread pro Kern haben wollte, also schrieb ich meine eigene Thread-Pool-Ersatzklasse. Der Code wird als Antwort auf eine andere Frage Stackoverflow bereitgestellt hier .

In Bezug auf die ursprüngliche Frage ist der Thread-Pool nützlich, um sich wiederholende Berechnungen in Teile aufzuteilen, die parallel ausgeführt werden können (vorausgesetzt, sie können parallel ausgeführt werden, ohne das Ergebnis zu ändern). Die manuelle Thread-Verwaltung ist nützlich für Aufgaben wie UI und IO.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.