Frage

Ich habe versucht, Multi-Threaded-Programmierung in C # zu lernen, und ich bin verwirrt, wenn es am besten, einen Thread-Pool zu verwenden, gegen meine eigenen Threads erstellen. Ein Buch empfiehlt die Verwendung eines Threadpool für kleine Aufgaben nur (was immer das bedeutet), aber ich kann keine wirklichen Richtlinien zu finden scheinen. Was sind einige Überlegungen, die Sie verwenden, wenn diese Programmierung Entscheidungsfindung?

War es hilfreich?

Lösung

Wenn Sie viele logische Aufgaben, die ständige Bearbeitung erfordern, und Sie möchten, dass der Pool + Scheduler parallel Gebrauch gemacht werden.

Wenn Sie Ihre IO bezogenen Aufgaben gleichzeitig wie das Herunterladen von Material von Remote-Servern oder Festplattenzugriff machen, sondern müssen dies alle paar Minuten einmal sagen, das zu tun, dann Ihre eigenen Threads machen und sie töten, wenn Sie fertig sind.

Edit:. Über einige Überlegungen, verwende ich Thread-Pools für den Datenbankzugriff, Physik / Simulation, AI (Spiele), und für eine Skript-Aufgaben lief auf virtuellen Maschinen, die viele benutzerdefinierte Aufgaben bearbeiten

Normalerweise besteht ein Pool von 2 Threads pro Prozessor (so wahrscheinlich 4 heute), jedoch können Sie den Betrag von Threads Sie einrichten, wenn Sie wissen, wie viele Sie benötigen.

Edit: Der Grund, Ihre eigenen Threads zu machen, ist wegen Kontextänderungen, (das ist, wenn Fäden in und aus dem Prozess tauschen müssen, zusammen mit ihren Speichern). nutzlos Kontextänderungen zu haben, sagen, wenn Sie Ihre Fäden nicht verwenden, nur so dass sie herumsitzen, wie man sagen könnte, kann leicht die Hälfte die Leistung Ihres Programms (sagen Sie 3 Schlaf Fäden und 2 aktive Threads). Wenn also diese Download-Threads nur warten sie auf Tonnen von CPU sind Essen und den Cache für Ihre reale Anwendung Abkühlphase

Andere Tipps

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

Wenn Sie die Anzahl der Threads begrenzen wollen laufen oder wollen nicht den Aufwand für die Erstellung und sie zu zerstören, verwenden Sie einen Thread-Pool.

Durch die kleinen Aufgaben, das Buch Sie lesen bedeutet, Aufgaben mit einer kurzen Lebensdauer. Wenn es 10 Sekunden dauert einen Thread zu erstellen, die nur für eine Sekunde läuft, dass ein Ort ist, wo Sie verwenden sollen Pools (meine tatsächlichen Zahlen ignorieren, es ist das Verhältnis, das zählt).

Ansonsten verbringen Sie den Großteil Ihrer Zeit mit der Erstellung und Threads, anstatt einfach macht die Arbeit zu zerstören sie bestimmt sind zu tun.

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

Die Post hat auch einige Punkte auf, wenn Sie nicht den Thread-Pool verwendet werden sollen und Ihren eigenen Thread stattdessen starten.

Ich empfehle das Lesen der hoch dieses kostenlose E-Book: Threading in C # durch Joseph Albahari

Mindestens lesen Sie den "Getting Started" Abschnitt. Das E-Book bietet eine großartige Einführung und enthält eine Fülle von fortgeschrittenen Threading Informationen auch.

Zu wissen, ob der Thread-Pool zu verwenden, ist nur der Anfang. Als Nächstes werden Sie, welche Methode der Eingabe des Thread-Pools am besten Ihre Bedürfnisse bestimmen müssen:

  • Task Parallel Library (.NET Framework 4.0)
  • ThreadPool.QueueUserWorkItem
  • Asynchronous Delegierten
  • Background

Diese E-Buch erklärt alle diese und berät, wenn sie benutzen gegen Ihre eigenen Thread erstellen.

Der Thread-Pool ist so konzipiert, Kontextwechsel zwischen Threads zu reduzieren. Betrachten wir ein Prozess, der mehrere Komponenten laufen hat. Jede dieser Komponenten könnte Worker-Threads zu erstellen. Je mehr Threads in Ihrem Prozess, der mehr Zeit für Kontextwechsel verschwendet wird.

Nun, wenn jede dieser Komponenten wurden Elemente in die Thread-Pool Schlange stehen, würden Sie viel weniger Kontextwechsel Overhead haben.

Der Thread-Pool ist so konzipiert, um die Arbeit zu maximieren über Ihre CPUs (oder CPU-Kern) durchgeführt werden. Aus diesem Grund wird standardmäßig der Thread-Pool mehrere Threads pro Prozessor dreht auf.

Es gibt einige Situationen, in denen Sie sich nicht den Thread-Pool verwendet werden sollen. Wenn Sie auf ich warten / O, oder wartet auf ein Ereignis, etc dann binden Sie diesen Thread-Pool-Thread und es kann nicht von jemand anderem verwendet werden. Gleiche Idee gilt für lange laufende Aufgaben, obwohl das, was eine lange laufende Aufgabe darstellt, ist subjektiv.

Pax Diablo macht einen guten Punkt auch. Spinnfäden nach oben ist nicht frei. Es braucht Zeit, und sie verbrauchen zusätzliche Speicher für ihre Stapelspeicher. Der Thread-Pool wird wieder verwenden Threads diese Kosten amortisieren.

Hinweis: Sie gefragt, um einen Thread-Pool-Thread unter Verwendung von Daten zum Download oder Disk-I / O durchzuführen. Sie sollten nicht einen Thread-Pool-Thread für diesen (aus den Gründen, die ich oben beschrieben) verwenden. Verwenden Sie stattdessen asynchrone I / O (auch bekannt als die BeginXX und EndXX Methoden). Für eine FileStream die BeginRead und EndRead würde. Für eine HttpWebRequest die BeginGetResponse und EndGetResponse würde. Sie sind kompliziert zu bedienen, aber sie sind der richtige Weg, Multi-Threaded-E / A auszuführen.

Vorsicht vor dem .NET-Thread-Pool für Operationen, die für einen signifikanten, variable oder unbekannten Teil ihrer Verarbeitung blockieren können, wie es ist anfällig Hunger fädeln. Betrachten Sie die .NET parallele Erweiterungen verwenden, die eine gute Anzahl von logischen Abstraktionen über Gewindeoperationen bereitzustellen. Sie umfassen auch einen neuen Scheduler, die eine Verbesserung gegenüber Thread sein sollte. Siehe hier

Ein Grund den Thread-Pool für kleine Aufgaben nur zu verwenden, ist, dass es eine begrenzte Anzahl von Threadpool Threads ist. Wenn man sich für eine lange Zeit verwendet wird, dann stoppt sie den Thread durch anderen Code verwendet wird. Wenn dies oft geschieht, dann kann der Thread-Pool aufgebraucht sein.

, um den Threadpool verwenden kann subtile Effekte haben -. Einig .NET-Timer verwendet Thread-Pool-Threads und wird nicht ausgelöst, zum Beispiel

Wenn Sie eine Hintergrundaufgabe haben, die für eine lange Zeit, wie für die gesamte Lebensdauer Ihrer Anwendung lebt, dann ist deinen eigenen Thread zu schaffen ist eine vernünftige Sache. Wenn Sie kurze Jobs haben, die in einem Thread durchgeführt werden müssen, verwenden Sie dann Threadpooling.

In einer Anwendung, in dem Sie viele Threads erstellen, der Aufwand, die Fäden zu schaffen, wird beträchtlich. Unter Verwendung des Thread-Pool, die Fäden einmal erzeugt und verwendet sie, damit den Kopf Thread-Erzeugung zu vermeiden.

In einer Anwendung, die ich gearbeitet, von wechselnden Themen zur Verwendung des Thread-Pools für die kurzlebigen Themen wirklich zu schaffen helpped den Durchsatz der Anwendung.

Für die höchste Leistung bei gleichzeitig ausgeführten Einheiten, Ihren eigenen Thread-Pool schreiben, wo ein Pool von Themen-Objekten erstellt beim Start und gehen Sie zu blockieren (früher) suspendiert, auf einem Kontext wartest einen Standard zu laufen (ein Objekt mit Schnittstelle von Ihrem Code implementiert).

So viele Artikel über Aufgaben vs. Themen vs. .NET Threadpool nicht wirklich Ihnen geben, was Sie eine Entscheidung für die Leistung machen müssen. Aber wenn man sie vergleichen zu können, gewinnen Themen und vor allem einen Pool von Threads. Sie sind die besten für CPUs verteilt und sie starten schneller.

Was diskutiert werden soll, ist die Tatsache, dass die Hauptausführungseinheit von Windows (einschließlich Windows 10) ein Gewinde, und O Kontext Kopfumschaltung wird in der Regel vernachlässigbar. Einfach gesagt, ich habe nicht in der Lage überzeugenden Beweis für viele diese Artikel zu finden, ob der Artikel durch eine höhere Leistung beansprucht Kontext sparenden Schalt oder besser CPU-Auslastung.

Jetzt für ein bisschen Realismus:

Die meisten von uns werden nicht unsere Anwendung müssen deterministisch sein, und die meisten von uns haben keine harten Schläge Hintergrund mit Gewinde, die beispielsweise häufig mit der Entwicklung eines Betriebssystems kommt. Was ich oben geschrieben habe ist nicht für einen Anfänger.

Also, was sein kann, am wichtigsten ist, ist zu diskutieren, was einfach zu programmieren ist.

Wenn Sie Ihren eigenen Thread-Pool erstellen, müssen Sie ein wenig schriftlich zu tun haben, wie Sie mit Tracking-Ausführungsstatus betroffen müssen werden, wie suspendieren zu simulieren und wieder aufnehmen, und wie die Ausführung abzubrechen - auch in einem applikationsweit geschlossen. Sie könnten auch mit sein müssen besorgt, ob Sie wollen dynamisch Ihren Pool wachsen und auch, welche Kapazitätsbegrenzung Ihren Pool haben. Ich kann schreiben einen solchen Rahmen in einer Stunde, aber das ist, weil ich es so oft getan haben.

Vielleicht ist der einfachste Weg, eine Ausführungseinheit zu schreiben, ist eine Aufgabe, zu verwenden. Die Schönheit einer Aufgabe besteht darin, dass Sie eine erstellen können und es in-line in Ihrem Code kick off (obwohl Vorsicht geboten sein kann). Sie können eine Stornierung Token passieren zu handhaben, wenn Sie die Aufgabe abgebrochen werden soll. Außerdem verwendet er das Versprechen Ansatz zu verketten Ereignisse, und Sie können es eine bestimmte Art von Wert zurückgeben müssen. Außerdem mit async und erwarten, mehr Möglichkeiten gibt es, und Ihr Code mehr tragbar sein.

Im Wesentlichen ist es wichtig, das Vor-und Nachteile mit Aufgaben vs. Threads vs. .NET Threadpool zu verstehen. Wenn ich hohe Leistung benötigen, werde ich Threads verwenden, und ich ziehe meine eigenen Pool verwenden.

Eine einfache Möglichkeit, zu vergleichen, ist starten 512 Threads, 512 Aufgaben und 512 Threadpool-Threads. Sie werden eine Verzögerung am Anfang mit Themen finden (daher, warum einen Thread-Pool schreiben), aber alle 512 Threads werden in wenigen Sekunden ausgeführt werden, während Aufgaben und .NET Threadpool-Threads auf ein paar Minuten dauern, bis alle beginnen.

Im Folgenden sind die Ergebnisse eines solchen Tests (i5 Quad-Core mit 16 GB RAM), die jeweils 30 Sekunden geben auszuführen. Der Code ausgeführt führt eine einfache Datei-I / O auf einem SSD-Laufwerk ein.

Testergebnisse

Thread-Pools sind groß, wenn Sie mehr Aufgaben als verfügbare Threads zu verarbeiten.

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

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

Sie immer einen Thread-Pool verwenden, wenn Sie können, arbeitet auf der höchsten Abstraktionsebene möglich. Thread-Pools verstecken Erstellen und zerstören Threads für Sie, das ist in der Regel eine gute Sache!

Die meiste Zeit können Sie den Pool nutzen, wie Sie den teuren Prozess der Erstellung des Fadens zu vermeiden.

Doch in einigen Szenarien möchten Sie vielleicht einen Thread erstellen. Zum Beispiel, wenn Sie nicht die einzigen, mit dem Thread-Pool sind und der Faden Sie erstellen, ist langlebig (zu vermeiden gemeinsame Ressourcen verbrauchen) oder zum Beispiel, wenn Sie den stack des Fadens steuern mögen.

Vergessen Sie nicht, den Hintergrund Arbeiter zu untersuchen.

ich für viele Situationen zu finden, gibt es nur mir, was ich ohne schweres Heben will.

Prost.

ich in der Regel die Thread verwenden, wenn ich nur brauchen, um etwas auf einem anderen Thread zu tun und kümmern sich nicht wirklich, wenn es läuft oder endet. So etwas wie die Protokollierung oder vielleicht sogar Hintergrund Herunterladen eine Datei (obwohl es gibt bessere Möglichkeiten, um den Asynchron-Stil zu tun). Ich verwende meine eigenen Thread, wenn ich mehr Kontrolle benötigen. Auch das, was ich gefunden habe, ist eine Threadwarteschlange mit Hilfe von (Hack Ihre eigenen) „Befehlsobjekte“ zu speichern, ist schön, wenn ich mehrere Befehle haben, die ich brauche in> 1 Faden zu arbeiten. So werden Sie können eine XML-Datei aufgeteilt und jedes Element setzen in einer Warteschlange und haben dann mehrere Threads arbeiten einig Verarbeitung auf diesen Elementen zu tun. Ich schrieb eine solche Warteschlange Art und Weise in uni zurück (VB.net!), Dass ich in C # konvertiert haben. Ich habe es auch weiter unten ohne besonderen Grund (dieser Code möglicherweise 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();
        }
    }
}

Ich wollte einen Thread-Pool Arbeit über Kerne mit so wenig Latenz wie möglich zu verteilen, und das mußte nicht gut spielen mit anderen Anwendungen. Ich fand, dass die .NET-Thread-Pool Leistung war nicht so gut, wie es sein könnte. Ich wusste, dass ich einen Thread pro Kern wollte, so dass ich meine eigene Thread-Pool Ersatz Klasse geschrieben. Der Code wird als Antwort auf eine andere Frage Stackoverflow bereitgestellt hier .

In Bezug auf die ursprüngliche Frage, die Thread-Pool ist nützlich für das Brechen von repetitiven Berechnungen in Teile, die parallel ausgeführt werden können (vorausgesetzt, sie können ohne Änderung des Ergebnisses parallel ausgeführt werden). Manuelles Thread-Management ist für Aufgaben wie UI und IO nützlich.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top