Ist Parallel die Task-Bibliothek (oder PLINQ) nehmen andere Prozesse berücksichtigt?

StackOverflow https://stackoverflow.com/questions/3488381

  •  28-09-2019
  •  | 
  •  

Frage

Insbesondere suche ich TPL bei Verwendung externer Prozesse zu starten (und warten). Hat die TPL Blick auf Gesamtmaschinenlast (beide CPU und I / O), bevor eine weitere Aufgabe zu starten entscheiden (daher - in meinem Fall - ein weiterer externer Prozess)?

Beispiel:

Ich habe über 100 Mediendateien bekam, die codiert werden müssen oder umcodiert (beispielsweise von WAV zu FLAC oder von FLAC zu MP3). Die Codierung wird durch die Einführung eines externen Prozesses geschehen (z.B. flac.exe oder lame.exe). Jede Datei dauert etwa 30 Sekunden. Jeder Prozess ist meist CPU-gebunden, aber es gibt einige E / A drin. Ich habe 4 Kerne erhalten, so der schlimmste Fall (Transcodierung durch den Decoder in den Codierer kochend) nach wie vor nur zwei Kerne verwendet. Ich möchte so etwas wie zu tun:

Parallel.ForEach(sourceFiles,
    sourceFile =>
        TranscodeUsingPipedExternalProcesses(sourceFile));

Wird diese Kick-off 100 Aufgaben (und damit 200 externe Prozesse für die CPU im Wettbewerb)? Oder wird es sehen, dass der CPU beschäftigt und nur 2-3 zu einer Zeit tun?

War es hilfreich?

Lösung

Sie werden hier in ein paar Probleme laufen. Der Hunger Vermeidungsmechanismus des Abwicklers wird Ihre Aufgaben sehen wie sie auf Prozesse warten blockiert. Es wird nur schwer zwischen einem Deadlocks Faden und man einfach warten auf einen Prozess vollständig zu unterscheiden. Als Ergebnis kann es neue Aufgaben planen, wenn Sie Ihre Aufgaben ausführen oder eine lange Zeit (siehe unten). Die Hillclimbing Heuristik sollte die Gesamtlast auf dem System berücksichtigen, sowohl aus Ihrer Anwendung und anderen. Es wird versucht, einfach Arbeit zu maximieren, so wird es mehr Arbeit hinzufügen, bis der Gesamtdurchsatz des Systems nicht weiter ansteigen und dann wird es wieder aus. Ich weiß nicht denken diese Anwendung bewirken wird, aber die stavation Vermeidung Problem wahrscheinlich.

Sie können mehr Details, wie das alles funktioniert in Parallele Programmierung mit Microsoft®.NET , Colin Campbell, Ralph Johnson, Ade Miller, Stephen Toub (ein früherer Entwurf ist Online ) .

"Der .NET Threadpool verwaltet automatisch die Anzahl der Arbeitnehmer Threads im Pool. Es hinzufügt und entfernt Gewinde nach Einbau- Heuristiken. .NET-Thread-Pool hat zwei Hauptmechanismen zum Injizieren Themen: ein Verhungern Vermeidungsmechanismus, der Arbeiter fügt Fäden, wenn es keine Fortschritte gemacht werden, auf die Warteschlange gestellt Produkte und Hillclimbing sieht Heuristik, dass versucht während der Verwendung zu maximieren Durchsatz wenige Threads wie möglich.

Das Ziel der Hungervermeidung ist Deadlock zu verhindern. Diese Art kann der Deadlock auftreten, wenn ein Arbeiter-Thread wartet auf eine Synchronisierung Ereignis, das von einem Workitem kann nur erfüllt werden, die noch anhängig in dem globalen oder lokalen Warteschlangen des Thread-Pools. Wenn es einen waren fixiert Anzahl der Arbeitsthreads, und all diese Fäden wurden ähnlich blockiert, wäre nicht in der Lage das System immer weiter Fortschritte zu machen. Hinzufügen eines neuen Arbeitsthread wird das Problem gelöst.

Ein Ziel der Hill-Climbing-Heuristik ist die Auslastung zu verbessern der Kerne, wenn Themen von I / O oder andere Wartebedingungen blockiert diesem Stand der Prozessor. Standardmäßig hat der verwaltete Thread-Pool eine Arbeiter-Thread pro Kern. Wenn eine dieser Arbeitsthreads wird blockiert, gibt es eine Chance, dass ein Kern ausgelastet werden könnte, je auf die Gesamtauslastung des Computers. Die Fadeninjektionslogik nicht zwischen einem Faden zu unterscheiden, die blockiert ist und ein Gewinde das ist die Durchführung eine lange, rechenintensive Operation. Deshalb, immer dann, wenn der globalen Thread-Pools oder lokale Warteschlangen enthalten anhängige Workitems, aktive Arbeitselemente, die eine lange Zeit dauern, laufen (mehr als eine halbe Sekunde) kann die Schaffung neuer Thread-Pool Arbeiter auslösen Threads.

Der .NET-Thread-Pool hat die Möglichkeit, Themen zu injizieren alle Zeit, um eine Arbeitseinheit abgeschlossen ist oder bei 500 Millisekunden-Intervallen, je nachdem, welche ist kürzer. Der Thread-Pool nutzt diese Gelegenheit, um zu versuchen, Themen Hinzufügen (Oder nehmen sie entfernt), geführt durch eine Entfernung um Änderungen in Die Fadenzahl. Wenn das Hinzufügen Fäden helfen Durchsatz zu sein scheint, der Faden-Pool fügt mehr; andernfalls, es reduziert die Anzahl der Arbeiter-Threads. Diese Technik wird die Hill-Climbing-Heuristik genannt. Daher ist ein Grund, auf einzelne Aufgaben zu halten Kurzschlüsse zu vermeiden „Hunger-Erkennung“, aber ein weiterer Grund, sie kurz zu halten ist geben dem Thread-Pool mehr Möglichkeiten zur Verbesserung der Durchsatz durch Einstellen der Fadenzahl. Je kürzer die Dauer der einzelnen Aufgaben können je öfter der Thread-Pool messen Durchsatz und stellen Sie die Fadenzahl entsprechend.

Um diese zu konkretisieren, ein extremes Beispiel. Annehmen dass Sie eine komplexe Finanzsimulation mit 500 prozessorintensiven haben Operationen, von denen jede dauert 10 Minuten im Durchschnitt fertigstellen. Wenn Sie Top-Level-Aufgaben in der globalen Warteschlange für jede erstellen dieser Operationen, werden Sie, dass af findenter etwa fünf Minuten die Thread-Pool wird auf 500 Arbeitsthreads wachsen. Der Grund dafür ist, dass die Thread-Pool sieht alle Aufgaben wie blockiert und beginnt neu hinzufügen Fäden mit einer Geschwindigkeit von etwa zwei Gewindegängen pro Sekunde.

Was ist falsch mit 500 Worker-Threads? Im Prinzip nichts, wenn Sie haben 500 Kerne für sie zu verwenden und große Mengen an System Erinnerung. In der Tat ist dies die langfristige Vision von Parallel Computing. Wenn Sie jedoch nicht aus, dass viele Kerne auf Ihrem Computer, Sie sind in einer Situation, wo viele Threads für Zeitscheiben konkurrieren. Dies Situation wird als Prozessor Überzeichnung bekannt. Unter Berücksichtigung vieler prozessorintensive Fäden für die Zeit konkurrieren auf einem einzelnen Kern fügt Kontextwechsel-Overhead, das Gesamtsystem stark reduzieren kann Durchsatz. Auch wenn Sie nicht ausgehen von Speicher, Leistung in diesem Situation kann viel, viel schlimmer als in sequentieller Berechnung. (Jeder Kontextwechsel dauert zwischen 6.000 und 8.000 Prozessorzyklen.) Die Kosten für den Kontextwechsel ist nicht die einzige Quelle von Overhead. Ein verwaltetes Thread in .NET verbraucht etwa ein Megabyte Stapel Raum, auch nicht, dass der Raum für aktuell ausgeführten Funktionen verwendet wird. Es dauert etwa 200.000 CPU-Zyklen einen neuen Thread zu erstellen, und etwa 100.000 Zyklen einen Faden zurückzuziehen. Dies sind teure Operationen.

Solange Ihre Aufgaben nicht nehmen jeweils Minuten, der Thread Becken Hill-Climbing-Algorithmus wird schließlich erkennen, dass es zu viele Threads hat und Schnitt zurück auf eigenem Antrieb. Wenn Sie jedoch haben Aufgaben zu tun, dass besetzen einen Worker-Thread für viele Sekunden oder Minuten oder Stunden, dass wird der Thread-Pool der Heuristik, und an diesem Punkt abzuwerfen Sie sollte eine Alternative in Betracht ziehen.

Die erste Option ist die Anwendung in kürzeren zu zersetzen Aufgaben, dass ein vollständiges schnell genug für den Threadpool erfolgreich steuern, um die Anzahl von Threads für einen optimalen Durchsatz. Eine zweite Möglichkeit ist Ihre eigenen Task-Scheduler zu implementieren Objekt, das keine Fadeneinspritzung nicht durchführt. Wenn Sie Ihre Aufgaben sind lang Dauer, brauchen Sie nicht eine hoch optimierte Task-Scheduler, weil die Kosten für die Terminierung vernachlässigbar im Vergleich zu der Ausführung wird Zeit der Aufgabe. MSDN® Entwicklerprogramm hat ein Beispiel für eine Scheduler Implementierung einfache Aufgabe, die den maximalen Grad begrenzt von Gleichzeitigkeit. Weitere Informationen finden Sie im Abschnitt „Weiterführende Literatur“ am Ende dieses Kapitels.

Als letzten Ausweg, können Sie die SetMaxThreads Methode verwenden, um die Klasse Threadpool mit einer Obergrenze für die Anzahl konfigurieren der Arbeitsthreads, Equal der Regel auf die Anzahl der Kerne (dies ist das Environment.ProcessorCount Eigenschaft). Diese Obergrenze gilt für der gesamte Prozess, alle AppDomains einschließlich. "

Andere Tipps

Die kurze Antwort lautet: no.

Intern verwendet die TPL den Standard ThreadPool seine Aufgaben zu planen. Sie sind also zu fragen, ob die tatsächlich ThreadPool Maschine berücksichtigt und es funktioniert nicht. Das einzige, was Grenzen die Anzahl der Aufgaben gleichzeitig ausgeführt werden, die Anzahl der Threads im Thread-Pool ist, sonst nichts.

Ist es möglich, die externen Prozesse berichten zu Ihrer Anwendung zu haben, sobald sie bereit sind? In diesem Fall müssen Sie für sie nicht warten (halte Fäden besetzt).

tun geschleift Spins

Ran einen Test mit TPL / Threadpool eine große Anzahl von Aufgaben zu planen. Mit Hilfe eines externen App ich einer der Kerne zu 100% Affinität unter Verwendung von proc geladen haben. Die Anzahl der aktiven Aufgaben nie verringert.

Noch besser lief ich mehrere Instanzen der gleichen CPU-Kapazität .NET TPL App aktiviert. Die Anzahl der Threads für alle Anwendungen war das gleiche, und nie unter der Anzahl der Kerne ging, obwohl meine Maschine kaum nutzbar war.

So Theorie beiseite verwendet TPL die Anzahl der Kerne zur Verfügung, aber nie überprüft auf ihrer tatsächlichen Belastung. Eine sehr schlechte Umsetzung meiner Meinung nach.

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