Werden untergeordnete Prozesse über Multiprozessor- Freigabeobjekte erzeugt, die zuvor im Programm erstellt wurden?
Ich habe folgendes Setup:
do_some_processing(filename):
for line in file(filename):
if line.split(',')[0] in big_lookup_object:
# something here
if __name__ == '__main__':
big_lookup_object = marshal.load('file.bin')
pool = Pool(processes=4)
print pool.map(do_some_processing, glob.glob('*.data'))
Ich lade ein großes Objekt in den Speicher und erstelle dann einen Pool von Arbeitern, die dieses große Objekt verwenden müssen. Auf das große Objekt wird schreibgeschützt zugegriffen. Ich muss keine Änderungen zwischen den Prozessen übergeben.
Meine Frage ist: Wird das große Objekt in den gemeinsam genutzten Speicher geladen, wie es der Fall wäre, wenn ich einen Prozess unter Unix / C erzeugen würde, oder lädt jeder Prozess seine eigene Kopie des großen Objekts?
Update: zur weiteren Verdeutlichung - big_lookup_object ist ein gemeinsam genutztes Lookup-Objekt. Ich muss das nicht aufteilen und separat verarbeiten. Ich muss eine einzige Kopie davon behalten. Die Arbeit, die ich zum Teilen brauche, besteht darin, viele andere große Dateien zu lesen und die Elemente in diesen großen Dateien anhand des Suchobjekts nachzuschlagen.
Weiteres Update: Datenbank ist eine gute Lösung, Memcached ist möglicherweise eine bessere Lösung und Datei auf der Festplatte (Shelve oder DBM) ist möglicherweise noch besser. Bei dieser Frage interessierte mich besonders eine In-Memory-Lösung. Für die endgültige Lösung werde ich hadoop verwenden, aber ich wollte sehen, ob ich auch eine lokale In-Memory-Version haben kann.
quelle
marshal.load
Eltern und jedes Kind auf (jeder Prozess importiert das Modul).Antworten:
"Werden untergeordnete Prozesse über Multiprozessor-Freigabeobjekte erzeugt, die zuvor im Programm erstellt wurden?"
Nein (Python vor 3.8) und Ja in 3.8 ( https://docs.python.org/3/library/multiprocessing.shared_memory.html#module-multiprocessing.shared_memory )
Prozesse haben einen unabhängigen Speicherplatz.
Lösung 1
Tun Sie dies, um eine große Struktur mit vielen Arbeitern optimal zu nutzen.
Schreiben Sie jeden Worker als "Filter" - liest Zwischenergebnisse von stdin, funktioniert, schreibt Zwischenergebnisse auf stdout.
Verbinden Sie alle Mitarbeiter als Pipeline:
Jeder Prozess liest, arbeitet und schreibt.
Dies ist bemerkenswert effizient, da alle Prozesse gleichzeitig ausgeführt werden. Die Schreib- und Lesevorgänge durchlaufen direkt gemeinsam genutzte Puffer zwischen den Prozessen.
Lösung 2
In einigen Fällen haben Sie eine komplexere Struktur - häufig eine "Fan-Out" -Struktur. In diesem Fall haben Sie einen Elternteil mit mehreren Kindern.
Übergeordnetes Element öffnet Quelldaten. Eltern gabeln eine Reihe von Kindern.
Das übergeordnete Element liest die Quelle und gibt Teile der Quelle an jedes gleichzeitig ausgeführte untergeordnete Element weiter.
Wenn der Elternteil das Ende erreicht hat, schließen Sie das Rohr. Das Kind bekommt das Dateiende und endet normal.
Die Kinderteile sind angenehm zu schreiben, weil jedes Kind einfach liest
sys.stdin
.Die Eltern haben ein wenig ausgefallene Beinarbeit, um alle Kinder zu laichen und die Pfeifen richtig zu halten, aber es ist nicht so schlimm.
Fan-In ist die entgegengesetzte Struktur. Eine Reihe von unabhängig laufenden Prozessen muss ihre Eingaben zu einem gemeinsamen Prozess verschachteln. Der Sammler ist nicht so einfach zu schreiben, da er aus vielen Quellen lesen muss.
Das Lesen von vielen benannten Pipes erfolgt häufig mithilfe des
select
Moduls, um festzustellen, welche Pipes ausstehende Eingaben haben.Lösung 3
Shared Lookup ist die Definition einer Datenbank.
Lösung 3A - Laden Sie eine Datenbank. Lassen Sie die Mitarbeiter die Daten in der Datenbank verarbeiten.
Lösung 3B - Erstellen Sie einen sehr einfachen Server mit werkzeug (oder ähnlichem), um WSGI-Anwendungen bereitzustellen, die auf HTTP GET reagieren, damit die Mitarbeiter den Server abfragen können.
Lösung 4
Freigegebenes Dateisystemobjekt. Unix OS bietet Shared Memory-Objekte. Dies sind nur Dateien, die dem Speicher zugeordnet sind, sodass das Austauschen von E / A anstelle von mehr konventionell gepufferten Lesevorgängen erfolgt.
Sie können dies aus einem Python-Kontext auf verschiedene Arten tun
Schreiben Sie ein Startprogramm, das (1) Ihr ursprüngliches gigantisches Objekt in kleinere Objekte zerlegt und (2) Arbeiter mit jeweils einem kleineren Objekt startet. Die kleineren Objekte könnten eingelegte Python-Objekte sein, um ein wenig Zeit beim Lesen von Dateien zu sparen.
Schreiben Sie ein Startprogramm, das (1) Ihr ursprüngliches gigantisches Objekt liest und mithilfe von
seek
Operationen eine seitenstrukturierte, bytecodierte Datei schreibt, um sicherzustellen, dass einzelne Abschnitte mit einfachen Suchvorgängen leicht zu finden sind. Dies ist, was ein Datenbankmodul tut - die Daten in Seiten aufteilen, jede Seite über a leicht zu finden machenseek
.Spawn-Mitarbeiter mit Zugriff auf diese große Datei mit Seitenstruktur. Jeder Arbeiter kann nach den relevanten Teilen suchen und dort seine Arbeit erledigen.
quelle
Werden untergeordnete Prozesse über Multiprozessor-Freigabeobjekte erzeugt, die zuvor im Programm erstellt wurden?
Es hängt davon ab, ob. Bei globalen schreibgeschützten Variablen kann dies häufig in Betracht gezogen werden (abgesehen vom verbrauchten Speicher), andernfalls sollte dies nicht der Fall sein.
In der Dokumentation zu Multiprocessing heißt es:
Better to inherit than pickle/unpickle
Explicitly pass resources to child processes
Global variables
Beispiel
Unter Windows (einzelne CPU):
Mit
sleep
:Ohne
sleep
:quelle
z
nicht geteilt wird. Dies beantwortet die Frage mit: "Nein, zumindest unter Windows wird eine übergeordnete Variable nicht von untergeordneten Variablen gemeinsam genutzt."z
Fall), als gemeinsam genutzt betrachtet werden.S.Lott ist richtig. Mit den Multiprozessor-Verknüpfungen von Python erhalten Sie effektiv einen separaten, doppelten Speicherblock.
Auf den meisten * nix-Systemen erhalten Sie durch die Verwendung eines Aufrufs auf niedrigerer Ebene
os.fork()
tatsächlich Copy-on-Write-Speicher, was möglicherweise Ihre Meinung ist. AFAIK konnte theoretisch in den einfachsten Programmen, die möglich sind, aus diesen Daten lesen, ohne sie duplizieren zu lassen.Im Python-Interpreter sind die Dinge jedoch nicht ganz so einfach. Objektdaten und Metadaten werden im selben Speichersegment gespeichert. Selbst wenn sich das Objekt nie ändert, führt ein Referenzzähler für das inkrementierte Objekt zu einem Speicherschreibvorgang und damit zu einer Kopie. Fast jedes Python-Programm, das mehr als "Hallo drucken" tut, führt zu Inkrementen der Referenzanzahl, sodass Sie den Vorteil des Copy-on-Write wahrscheinlich nie erkennen werden.
Selbst wenn es jemandem gelungen wäre, eine Shared-Memory-Lösung in Python zu hacken, wäre der Versuch, die Speicherbereinigung prozessübergreifend zu koordinieren, wahrscheinlich ziemlich schmerzhaft.
quelle
Wenn Sie unter Unix ausgeführt werden, können sie aufgrund der Funktionsweise von Fork dasselbe Objekt gemeinsam nutzen (dh die untergeordneten Prozesse verfügen über einen separaten Speicher, sie werden jedoch beim Schreiben kopiert, sodass sie möglicherweise gemeinsam genutzt werden, solange niemand sie ändert). Ich habe folgendes versucht:
und bekam die folgende Ausgabe:
Dies beweist natürlich nicht , dass keine Kopie erstellt wurde, aber Sie sollten dies in Ihrer Situation überprüfen können, indem Sie die Ausgabe von überprüfen, um festzustellen,
ps
wie viel realen Speicher jeder Unterprozess verwendet.quelle
Unterschiedliche Prozesse haben unterschiedliche Adressräume. Als würde man verschiedene Instanzen des Interpreters ausführen. Dafür ist IPC (Interprozesskommunikation) gedacht.
Zu diesem Zweck können Sie entweder Warteschlangen oder Pipes verwenden. Sie können rpc auch über tcp verwenden, wenn Sie die Prozesse später über ein Netzwerk verteilen möchten.
http://docs.python.org/dev/library/multiprocessing.html#exchanging-objects-between-processes
quelle
Nicht direkt mit Multiprocessing an sich verbunden, aber aus Ihrem Beispiel geht hervor, dass Sie einfach das Regalmodul oder ähnliches verwenden könnten . Muss das "big_lookup_object" wirklich vollständig im Speicher sein?
quelle
Nein, aber Sie können Ihre Daten als untergeordneten Prozess laden und ihm erlauben, seine Daten mit anderen untergeordneten Prozessen zu teilen. siehe unten.
quelle
Für die Linux / Unix / MacOS-Plattform ist forkmap eine schnelle und schmutzige Lösung.
quelle