2016-10-08 3 views
2

Ich habe ein Programm in Python geschrieben, die 4 Eingabe Textdateien liest und schreibt sie alle in eine Liste mit dem Namen ListOutput, die einen gemeinsamen Speicher zwischen 4 Prozesse in meinem Programm verwendet (ich verwendete 4 Prozesse so meine Programm läuft schneller!)MultiProcessing langsamer mit mehr Prozessen

Ich habe auch eine gemeinsam genutzte Speichervariable namens processedFiles, die die Namen der bereits gelesenen Eingabedateien von einem der Prozesse speichert, so dass der aktuelle Prozess sie nicht wieder liest (Ich verwendete Sperre so Prozesse nicht Überprüfen Sie das Vorhandensein einer Datei innerhalb processedFiles zur gleichen Zeit).

Wenn ich nur einen Prozess verwende, läuft mein Programm schneller (7 Millisekunden) — mein Computer hat 8 Kerne. Warum ist das?

import glob 
from multiprocessing import Process, Manager,Lock 
import timeit 
import os 

os.chdir("files") 
# Define a function for the Processes 
def print_content(ProcessName,processedFiles,ListOutput,lock): 
    for file in glob.glob("*.txt"): 
     newfile=0 

     lock.acquire() 

     print "\n Current Process:",ProcessName 

     if file not in processedFiles: 
     print "\n", file, " not in ", processedFiles," for ",ProcessName 
     processedFiles.append(file) 
     newfile=1 #it is a new file 

     lock.release() 

     #if it is a new file 
     if newfile==1: 
     f = open(file,"r") 
     lines = f.readlines() 
     ListOutput.append(lines) 
     f.close() 

     #print "%s: %s" % (ProcessName, time.ctime(time.time())) 

# Create processes as follows 
try: 
    manager = Manager() 
    processedFiles = manager.list() 
    ListOutput = manager.list() 
    start = timeit.default_timer() 

    lock=Lock() 
    p1 = Process(target=print_content, args=("Procees-1",processedFiles,ListOutput,lock)) 
    p2 = Process(target=print_content, args=("Process-2",processedFiles,ListOutput,lock)) 
    p3 = Process(target=print_content, args=("Process-3",processedFiles,ListOutput,lock)) 
    p4 = Process(target=print_content, args=("Process-4",processedFiles,ListOutput,lock)) 

    p1.start() 
    p2.start() 
    p3.start() 
    p4.start() 

    p1.join() 
    p2.join() 
    p3.join() 
    p4.join() 

    print "ListOutput",ListOutput 
    stop = timeit.default_timer() 
    print stop - start 
except: 
    print "Error: unable to start process" 
+4

Bei einer Laufzeit von '7ms' investieren Sie einen beträchtlichen Teil der Zeit, um Prozesse zu starten und zu koordinieren. Sie haben auch viele "versteckte" sequentielle Teile. Denken Sie darüber nach: Sie können Dateien nur sequentiell öffnen, weil sie gesperrt sind, und jede gelesene Zeile muss auch synchronisiert werden, wenn in den gemeinsamen Speicher geschrieben wird - es gibt praktisch keine Verstärkung durch Mehrfachverarbeitung. Darüber hinaus starten Sie Prozesse und leiten Daten zwischen ihnen weiter. All das braucht Zeit. – MisterMiyagi

+2

Zu @ MisterMiyagis ausgezeichneten Kommentaren füge ich hinzu, dass die Datei selten compute-gebunden ist. Der Prozessor verbringt die meiste Zeit damit, auf das io-Subsystem zu warten. Im Allgemeinen gibt es nur einen Vorteil beim Hinzufügen von Prozessoren für Jobs, die sie tatsächlich benötigen. Hier fügt das Hinzufügen von mehr Prozessoren reinen Overhead des Typs hinzu, den MM beschreibt. – Gene

+2

Ein wenig off-topic: Es ist einfacher und besser, 'Lock's als Kontextmanager zu verwenden. Aus der [Dokumentation] (https://docs.python.org/2/library/multiprocessing.html#multiprocessing.Lock): "' Lock' unterstützt das Kontext-Manager-Protokoll und kann daher in 'with'-Anweisungen verwendet werden. " Fügen Sie dazu einfach eine Anweisung 'with lock:' vor jeder Gruppe von Anweisungen hinzu, die exklusiven Zugriff auf etwas erfordern. – martineau

Antwort

4

Das Problem ist, dass das, was aussieht oft nicht der Fall ist Multiprozessing. Nur mehr Kerne zu verwenden bedeutet nicht, mehr Arbeit zu leisten.

Das grellste Problem ist, dass Sie alles synchronisieren. Die Auswahl von Dateien erfolgt sequenziell, weil Sie sperren, daher gibt es hier keine Verstärkung. Während Sie parallel lesen, wird jede gelesene Zeile in eine gemeinsame Datenstruktur geschrieben - die sich intern selbst synchronisiert. So ist der einzige Gewinn, den Sie potenziell bekommen, vom parallelen Lesen. Abhängig von Ihren Medien, z.B. eine Festplatte statt einer SSD, die Summe mehrerer Leser ist tatsächlich langsamer als eine einzige.

Hinzu kommt der Overhead aus der Verwaltung all dieser Prozesse. Jeder muss gestartet werden. Jeder muss seine Eingabe übergeben werden. Jeder muss mit den anderen kommunizieren, was praktisch für jede Aktion geschieht. Und lassen Sie sich nicht täuschen, ein Manager ist elegant, aber Schwergewicht.

Also abgesehen von wenig zu gewinnen, fügen Sie eine zusätzliche Kosten. Da Sie mit einer sehr geringen Laufzeit von nur 7ms beginnen, können diese zusätzlichen Kosten ziemlich erheblich sein.

Im Allgemeinen lohnt sich multiprocessing nur, wenn Sie CPU-gebunden sind. Das heißt, Ihre CPU-Effizienz liegt nahe bei 100%, d. H. Es gibt mehr Arbeit als das, was getan werden kann. Im Allgemeinen passiert dies, wenn Sie viel rechnen. Normalerweise ist es ein guter Indikator dafür, dass Sie nicht CPU-gebunden sind.

+2

Mahin Ra: Beachten Sie auch, dass die Verwendung eines 'multiprocessing.Manager' einen Serverprozess zur Verwaltung der gemeinsamen Objekte über Proxies erstellt. Dies fügt nur mehr Overhead hinzu (und warum sollten Sie den gemeinsamen Status vermeiden). – martineau

2

einfach auf bestehende Antwort hinzuzufügen, gibt es bestimmte Fälle, in denen wirklich mit multiprocessing Mehrwert und spart Zeit:

  1. Ihr Programm tut N Aufgaben, die voneinander unabhängig sind.
  2. Ihr Programm führt umfangreiche schwere mathematische Berechnungen durch
  3. Als Gotcha zum zweiten Punkt muss die Rechenzeit deutlich größer sein. Andernfalls werden die Kosten für die Erstellung eines neuen Prozesses den Vorteil des Multiprocessing überschatten und Ihr parallel verarbeitendes Programm wird langsamer laufen als eine sequenzielle Version.
  4. Im Idealfall, wenn Ihr Programm Datei-I/O, Netzwerk-I/O-Operationen, dann parallelisieren Sie Ihr Programm nicht, es sei denn, Sie haben sehr starken Grund, dies zu tun.
  5. Um zum vierten Punkt hinzuzufügen, wenn Ihre Anforderung erfordert, dann können Sie an die Erstellung eines multiprocess.Pool denken, die Aufgabe für Sie ausführen wird, wie benötigt und beseitigt den Overhead der Erstellung und Zerstörung von Prozessen jedes Mal.

Ich hoffe, es hilft Ihnen.

Verwandte Themen