2009-08-04 45 views
32

Ich habe eine Python-Anwendung, die eine Sammlung von Daten ergreift und für jeden Teil der Daten in dieser Sammlung eine Aufgabe ausführt. Die Aufgabe dauert einige Zeit, da eine Verzögerung erforderlich ist. Aufgrund dieser Verzögerung möchte ich nicht, dass jedes Datenelement die Aufgabe anschließend ausführt, ich möchte, dass sie alle parallel ausgeführt werden. Sollte ich Multiprozess verwenden? oder Threading für diese Operation?Multiprozess oder Threading in Python?

Ich habe versucht, Threading zu verwenden, hatte aber einige Probleme, oft würden einige der Aufgaben nie tatsächlich auslösen.

+0

Wie groß ist Ihre "Sammlung von Daten". Wenn es sehr groß ist, möchten Sie möglicherweise keine Threads oder Prozesse für jedes einzelne starten. –

+0

normalerweise 1, 2 oder 3 Datenstücke. – Ryan

+0

@ S.Lott - wie würden Sie die Anzahl der Threads/Prozesse auf eine Zahl begrenzen, die viel kleiner ist als die Größe der Daten? –

Antwort

0

Die Verwendung von CPythons Threading-Modell bringt keine Leistungsverbesserung, da die Threads aufgrund der Art und Weise, wie Garbage Collection behandelt wird, nicht parallel ausgeführt werden. Multiprozess würde parallele Ausführung ermöglichen. Offensichtlich müssen Sie in diesem Fall mehrere Kerne zur Verfügung haben, um Ihre parallelen Jobs zu bearbeiten.

Es gibt viel mehr Informationen in this related question.

+4

Das ist nicht wahr. Es wird nicht so viel Leistungsverbesserung wie in, sagen wir, C oder C++ geben, aber etwas Nebenläufigkeit tritt auf. Besonders wenn Sie I/O-gebunden sind, helfen Sie mit. – Christopher

+0

Ich hatte das nicht bemerkt - danke für die Info. Hier ist eine externe Referenz: http://mail.python.org/pipermail/python-dev/2008-May/079461.html. In diesem Benchmark können Sie die Verbesserung für I/O-gebundene Probleme sehen, die Sie beschreiben. Es ist jedoch erwähnenswert, dass das CPU-gebundene Problem mit 2 Python-Threads ** langsamer lief als mit 1! Es scheint, dass Profiling für Ihre Anwendung unerlässlich ist. –

7

Für kleine Sammlungen von Daten, erstellen Sie einfach Subprozesse mit subprocess.Popen.

Jeder Subprozess kann einfach seine Daten von stdin oder von Befehlszeilenargumenten abrufen, verarbeiten und einfach das Ergebnis in eine Ausgabedatei schreiben.

Wenn alle Subprozesse abgeschlossen sind (oder das Zeitlimit überschritten ist), führen Sie einfach die Ausgabedateien zusammen.

Sehr einfach.

+3

Dies ist eine wirklich schwere Lösung. Sie müssen nicht nur die Daten einem externen Prozess zuführen, Sie haben auch massive Kosten. – Christopher

+1

@ Christopher. Der Punkt ist Einfachheit. Die Unix-Welt verwendet diese Technik seit 40 Jahren. Es funktioniert gut, weil es einfach ist. Außerdem ist der Overhead nicht wirklich "massiv", da Sie mehrere Instanzen desselben Binärbildes ausführen. Dies wird von GNU/Linux gut optimiert. –

+8

@ S.Lott: Nur weil es schon lange benutzt wurde, heißt das nicht, dass es eine gute Lösung ist. Es ist insbesondere keine gute Lösung für Rechenprobleme. Der Overhead ist "massiv", da Sie den Speicher-Overhead aller pro-Prozess-Strukturen sowie die Latenz mehrerer Kernel-Übergänge haben. Das Python-Multiprocessing-Modul erzeugt nicht wirklich einen neuen "Prozess" wie der Subprozess. Es erstellt einen neuen Interpreterkontext, der wesentlich leichter ist als das Erstellen eines neuen Prozesses auf Betriebssystemebene. – Christopher

7

Sie könnten in Betracht ziehen, in Stackless Python zu suchen. Wenn Sie die Kontrolle über die Funktion haben, die lange dauert, können Sie einfach einige stackless.schedule() s hineinwerfen (sprich yield zur nächsten Coroutine), oder Sie können set Stackless to preemptive multitasking.

In Stackless, Sie nicht über Gewinde haben, aber Tasklets oder greenlets, die im Wesentlichen sehr leichte Fäden sind. Es funktioniert großartig in dem Sinne, dass es ein ziemlich gutes Framework mit sehr wenig Setup gibt, um Multitasking in Gang zu bringen.

Stackless behindert jedoch die Portabilität, da Sie einige der Standard-Python-Bibliotheken ersetzen müssen - Stackless entfernt die Abhängigkeit vom C-Stack. Es ist sehr portabel, wenn der nächste Benutzer auch Stackless installiert hat, aber das wird selten der Fall sein.

29

Wenn Sie wirklich gebunden compute werden, ist die multiprocessing module mit wahrscheinlich das leichteste Gewicht Lösung (sowohl in Bezug auf den Speicherverbrauch und die Umsetzung Schwierigkeiten.)

Wenn Sie I/O Bindung unter Verwendung des threading module in der Regel geben du gute Ergebnisse. Stellen Sie sicher, dass Sie Thread-sicheren Speicher (wie die Warteschlange) verwenden, um Daten an Ihre Threads zu übergeben. Oder geben Sie ihnen ein einzelnes Datenelement, das für sie einmalig ist, wenn sie erzeugt werden.

PyPy ist auf die Leistung konzentriert. Es verfügt über eine Reihe von Funktionen, die bei der computergebundenen Verarbeitung hilfreich sein können. Sie haben auch Unterstützung für Software Transactional Memory, obwohl das noch nicht Produktionsqualität ist. Das Versprechen ist, dass Sie einfachere parallele oder gleichzeitige Mechanismen als Multiprocessing verwenden können (die einige peinliche Anforderungen hat).

Stackless Python ist auch eine nette Idee. Stackless hat Portabilitätsprobleme wie oben angegeben. Unladen Swallow war vielversprechend, aber ist jetzt nicht mehr gültig.Pyston ist eine andere (nicht abgeschlossene) Python-Implementierung mit Schwerpunkt auf Geschwindigkeit. Es ist ein anderer Ansatz als PyPy, der zu besseren (oder einfach anderen) Beschleunigungen führen kann.

0

Wenn Sie die Daten, die Sie haben, einfach partitionieren und separieren können, klingt es, als sollten Sie diese Partitionierung nur extern durchführen und sie mehreren Prozessen Ihres Programms zuführen. (d. h. mehrere Prozesse statt Threads)

0

IronPython hat echtes Multithreading, anders als CPython und es ist GIL. Je nachdem, was Sie tun, kann es sich lohnen, es zu betrachten. Aber es scheint, dass Ihr Anwendungsfall besser für das Multiprocessing-Modul geeignet ist.

Für den Typ, der Stackless Python empfiehlt, bin ich kein Experte, aber es scheint mir, dass er über Software "Multithreading" spricht, die überhaupt nicht parallel ist (immer noch in einem physikalischen Thread läuft, also kann nicht auf mehrere Kerne skalieren.) Es ist nur eine alternative Möglichkeit, asynchrone (aber immer noch single-threaded, nicht-parallele) Anwendung zu strukturieren.

9

Aufgaben laufen wie sequenziell, aber Sie haben die Illusion, die parallel ausgeführt werden. Aufgaben sind gut, wenn Sie für Datei- oder Verbindungs-E/A verwenden und weil Leichtgewichte sind.

Multiprozess mit Pool kann die richtige Lösung für Sie sein, da Prozesse parallel laufen, also sehr gut mit intensiver Berechnung, da jeder Prozess in einer CPU (oder Core) ausgeführt wird.

Setup-Multi-Prozess kann sehr einfach sein:

from multiprocessing import Pool 

def worker(input_item): 
    output = do_some_work() 
    return output 

pool = Pool() # it make one process for each CPU (or core) of your PC. Use "Pool(4)" to force to use 4 processes, for example. 
list_of_results = pool.map(worker, input_list) # Launch all automatically 
+0

bedeutet es, dass alle Kerne an denselben Daten arbeiten? Ist es möglich, input_list aufzuteilen und jeden Chunk an verschiedene Cores weiterzuleiten? – Moj

0

Sie möchten bei Twisted suchen. Es ist für asynchrone Netzwerkaufgaben konzipiert.