Was Sie suchen, ist ein Produzenten- / Konsumentenmuster
Grundlegendes Threading-Beispiel
Hier ist ein grundlegendes Beispiel für die Verwendung des Threading-Moduls (anstelle von Multiprocessing).
import threading
import Queue
import sys
def do_work(in_queue, out_queue):
while True:
item = in_queue.get()
result = item
out_queue.put(result)
in_queue.task_done()
if __name__ == "__main__":
work = Queue.Queue()
results = Queue.Queue()
total = 20
for i in xrange(4):
t = threading.Thread(target=do_work, args=(work, results))
t.daemon = True
t.start()
for i in xrange(total):
work.put(i)
work.join()
for i in xrange(total):
print results.get()
sys.exit()
Sie würden das Dateiobjekt nicht mit den Threads teilen. Sie würden Arbeit für sie produzieren, indem Sie die Warteschlange mit Datenzeilen versorgen . Dann würde jeder Thread eine Zeile aufnehmen, verarbeiten und dann in die Warteschlange zurückgeben.
In das Multiprocessing-Modul sind einige erweiterte Funktionen integriert , mit denen Daten wie Listen und spezielle Arten von Warteschlangen gemeinsam genutzt werden können . Es gibt Kompromisse bei der Verwendung von Multiprocessing gegenüber Threads, und dies hängt davon ab, ob Ihre Arbeit an CPU oder E / A gebunden ist.
Grundlegendes Multiprocessing.Pool-Beispiel
Hier ist ein wirklich einfaches Beispiel für einen Multiprozessor-Pool
from multiprocessing import Pool
def process_line(line):
return "FOO: %s" % line
if __name__ == "__main__":
pool = Pool(4)
with open('file.txt') as source_file:
results = pool.map(process_line, source_file, 4)
print results
Ein Pool ist ein Convenience-Objekt, das seine eigenen Prozesse verwaltet. Da eine geöffnete Datei über ihre Zeilen iterieren kann, können Sie sie an die übergeben pool.map()
, die sie durchläuft und Zeilen an die Worker-Funktion übermittelt. Map blockiert und gibt das gesamte Ergebnis zurück, wenn es fertig ist. Beachten Sie, dass dies ein stark vereinfachtes Beispiel ist und dass die pool.map()
gesamte Datei auf einmal in den Speicher eingelesen wird, bevor die Arbeit verteilt wird. Wenn Sie große Dateien erwarten, denken Sie daran. Es gibt fortgeschrittenere Möglichkeiten, ein Produzenten- / Konsumenten-Setup zu entwerfen.
Manueller "Pool" mit Limit und Zeilensortierung
Dies ist ein manuelles Beispiel für die Pool.map . Anstatt jedoch eine gesamte Iterable auf einmal zu verbrauchen, können Sie eine Warteschlangengröße festlegen, sodass Sie sie nur Stück für Stück so schnell wie möglich füttern. Ich habe auch die Zeilennummern hinzugefügt, damit Sie sie später verfolgen und auf sie verweisen können, wenn Sie möchten.
from multiprocessing import Process, Manager
import time
import itertools
def do_work(in_queue, out_list):
while True:
item = in_queue.get()
line_no, line = item
if line == None:
return
time.sleep(.5)
result = (line_no, line)
out_list.append(result)
if __name__ == "__main__":
num_workers = 4
manager = Manager()
results = manager.list()
work = manager.Queue(num_workers)
pool = []
for i in xrange(num_workers):
p = Process(target=do_work, args=(work, results))
p.start()
pool.append(p)
with open("source.txt") as f:
iters = itertools.chain(f, (None,)*num_workers)
for num_and_line in enumerate(iters):
work.put(num_and_line)
for p in pool:
p.join()
print sorted(results)