Wie beschränke ich die Anzahl der aktiven Threads in Python?

8

Bin neu bei Python und mache Fortschritte mit threading - mache eine Musikdatei-Konvertierung und möchte die mehreren Kerne auf meinem Rechner nutzen können (ein aktiver Konvertierungs-Thread pro Kern).

%Vor%

Alles funktioniert, alle Dateien werden verschlüsselt, bravo! ... jedoch erscheinen alle Prozesse sofort, aber ich möchte nur zwei gleichzeitig ausführen (einen für jeden Kern). Sobald eines fertig ist, möchte ich, dass es zum nächsten auf der Liste weitergeht, bis es fertig ist, dann fahre mit dem Programm fort.

Wie mache ich das?

(Ich habe mir die Thread-Pool- und Warteschlangenfunktionen angeschaut, aber ich kann keine einfache Antwort finden.)

Edit: Vielleicht sollte ich hinzufügen, dass jeder meiner Threads subprocess.Popen verwendet, um eine separate Befehlszeile Dekodierer (flac) piped zu stdout auszuführen, in die hineingefüttert wird eine Befehlszeile encoder (lame / mp3).

    
thornomad 24.11.2009, 02:24
quelle

6 Antworten

4

"Jeder meiner Threads verwendet subprocess.Popen , um eine separate Befehlszeile auszuführen [process]".

Warum haben ein paar Threads eine Reihe von Prozessen gemanagt? Genau das tut ein OS für Sie. Warum micro-managen, was das OS bereits verwaltet?

Anstatt mit Threads, die Prozesse überwachen, herumzualbern, müssen Sie nur Prozesse abzweigen. Ihre Prozesstabelle kann wahrscheinlich nicht mit 2000 Prozessen umgehen, aber sie kann einige Dutzend (vielleicht ein paar hundert) ziemlich einfach handhaben.

Sie möchten, dass more funktioniert, als Ihre CPUs möglicherweise verarbeiten können. Die wirkliche Frage ist eine der Erinnerung - keine Prozesse oder Threads. Wenn die Summe aller aktiven Daten für alle Prozesse den physischen Speicher übersteigt, müssen Daten ausgetauscht werden, und das verlangsamt Sie.

Wenn Ihre Prozesse einen relativ geringen Speicherbedarf haben, können Sie sehr viel laufen lassen. Wenn Ihre Prozesse einen großen Speicherbedarf haben, können Sie nicht sehr viele ausführen.

    
S.Lott 24.11.2009, 03:06
quelle
30

Wenn Sie die Anzahl der parallelen Threads begrenzen möchten, verwenden Sie einen Semaphor :

%Vor%

Starten Sie alle Threads gleichzeitig. Alle außer maximumNumberOfThreads warten in threadLimiter.acquire() und ein wartender Thread wird nur fortgesetzt, sobald ein anderer Thread threadLimiter.release() durchläuft.

    
Andre Holzner 13.05.2011 12:22
quelle
1

Wenn Sie die standardmäßige "cpython" -Version verwenden, hilft Ihnen das nicht, da immer nur ein Thread ausgeführt werden kann; Nachschlagen Global Interpreter Lock . Stattdessen würde ich vorschlagen, das Modul multiprocessing in Python 2.6 zu betrachten - es macht die parallele Programmierung zum Kinderspiel. Sie können ein Pool -Objekt mit 2*num_threads processes erstellen und ihm eine Reihe von Aufgaben zuweisen. Es wird bis zu 2*num_threads Aufgaben gleichzeitig ausführen, bis alle fertig sind.

Bei der Arbeit habe ich vor kurzem eine Reihe von Python-XML-Tools (ein anderes, xpath grepper und bulk xslt-Transformer) migriert, um dies zu nutzen, und habe sehr schöne Ergebnisse mit zwei Prozessen pro Prozessor erzielt.

    
Edmund 24.11.2009 02:38
quelle
1

Es sieht für mich so aus, als ob Sie einen Pool von einer Art haben möchten, und in diesem Pool möchten Sie die n Threads haben, wobei n == die Anzahl der Prozessoren in Ihrem System ist. Sie hätten dann einen anderen Thread, dessen einzige Aufgabe es wäre, Jobs in eine Warteschlange einzutragen, die die Worker-Threads übernehmen und verarbeiten könnten, wenn sie frei würden (also für einen Dual-Code-Rechner hätten Sie drei Threads, aber der Haupt-Thread würde es tun) sehr wenig).

Da du neu bei Python bist, nehme ich an, dass du nichts über die GIL weißt und es ist Seite- Effekte bezüglich Threading. Wenn Sie den Artikel lesen, den ich verlinkt habe, werden Sie schnell verstehen, warum traditionelle Multithreading-Lösungen nicht immer die besten in der Python-Welt sind. Stattdessen sollten Sie das Multiprocessing -Modul (neu in Python 2.6, in 2.5 können Sie diesen Backport verwenden ), um den gleichen Effekt zu erzielen. Es ist ein Schritt für das GIL-Problem, indem es mehrere Prozesse so verwendet, als wären sie Threads innerhalb derselben Anwendung. Es gibt einige Einschränkungen in Bezug auf die Art und Weise, wie Sie Daten teilen (Sie arbeiten in verschiedenen Speicherbereichen), aber das ist eigentlich keine schlechte Sache: Sie fördern nur gute Praktiken wie das Minimieren der Kontaktpunkte zwischen Threads (oder Prozessen in diesem Fall).

>

In Ihrem Fall sind Sie wahrscheinlich daran interessiert, einen Pool wie hier hier .

    
jkp 24.11.2009 02:39
quelle
1

Kurze Antwort: Verwenden Sie keine Threads.

Für ein funktionierendes Beispiel können Sie etwas betrachten, das ich kürzlich bei der Arbeit zusammengeworfen habe. Es ist ein kleiner Wrapper um ssh , der eine konfigurierbare Anzahl von Popen() Subprozessen ausführt. Ich habe es veröffentlicht auf: Bitbucket: classh (Cluster Admin ssh Wrapper) .

Wie bereits erwähnt, verwende ich keine Threads; Ich spawn nur die Kinder, Schleife über sie Aufruf ihrer .poll() -Methoden und Überprüfung auf Timeouts (auch konfigurierbar) und füllen Sie den Pool, wie ich die Ergebnisse sammeln. Ich habe mit verschiedenen sleep() Werten gespielt und in der Vergangenheit habe ich eine Version geschrieben (bevor das Modul subprocess zu Python hinzugefügt wurde), die das Signal Modul verwendet ( SIGCHLD und SIGALRM) und die os.fork () und os.execve () Funktionen --- die meine auf Rohr-und Datei-Beschreiber Sanitär, etc).

In meinem Fall drucke ich inkrementell Ergebnisse, wenn ich sie sammle ... und erinnere mich an alle, um sie am Ende zusammenzufassen (wenn alle Jobs beendet wurden oder getötet wurden, weil die Zeitüberschreitung überschritten wurde).

Ich habe das, wie gepostet, auf einer Liste von 25.000 internen Hosts ausgeführt (von denen viele down sind, sich im Ruhestand befinden, sich international befinden und für mein Testkonto usw. nicht zugänglich sind). Es beendete die Arbeit in etwas mehr als zwei Stunden und hatte keine Probleme. (Es gab ungefähr 60 von ihnen, die Timeouts aufgrund von Systemen in degenerierten / thrashenden Zuständen waren - was beweist, dass meine Timeout-Behandlung korrekt funktioniert).

Ich weiß also, dass dieses Modell zuverlässig funktioniert. Das Ausführen von 100 aktuellen ssh -Prozessen mit diesem Code scheint keine spürbaren Auswirkungen zu haben. (Es ist eine ziemlich alte FreeBSD-Box). Ich habe auch die alte (pre subprocess ) Version mit 100 gleichzeitigen Prozessen auf meinem alten 512MB Laptop ohne Probleme ausgeführt.

(Übrigens: Ich plane, dies zu bereinigen und Features hinzuzufügen; könnt ihr gerne einen Beitrag dazu leisten oder einen eigenen Zweig davon klonen; dafür ist Bitbucket.org da).

    
Jim Dennis 24.11.2009 10:14
quelle
0

Ich bin kein Experte darin, aber ich habe etwas über "Lock" s gelesen. Dieser Artikel könnte Ihnen vielleicht helfen

Hoffe, das hilft

    
inspectorG4dget 24.11.2009 02:38
quelle

Tags und Links