ProcessPoolExecutor aus der gleichzeitigen.futures Weise langsamer als multiprocessing.Pool
Ich war das Experimentieren mit neuen glänzenden gleichzeitige.futures - Modul eingeführt, in Python 3.2, und ich habe bemerkt, daß, mit fast identischen code, mit dem Pool von gleichzeitigen.futures ist Weg langsamer als mit multiprocessing.Pool.
Dies ist die version mit multiprocessing:
def hard_work(n):
# Real hard work here
pass
if __name__ == '__main__':
from multiprocessing import Pool, cpu_count
try:
workers = cpu_count()
except NotImplementedError:
workers = 1
pool = Pool(processes=workers)
result = pool.map(hard_work, range(100, 1000000))
Und diese ist mit gleichzeitigen.futures:
def hard_work(n):
# Real hard work here
pass
if __name__ == '__main__':
from concurrent.futures import ProcessPoolExecutor, wait
from multiprocessing import cpu_count
try:
workers = cpu_count()
except NotImplementedError:
workers = 1
pool = ProcessPoolExecutor(max_workers=workers)
result = pool.map(hard_work, range(100, 1000000))
Mit einem naiven Faktorisierung Funktion dieser Eli Bendersky Artikel, dies sind die Ergebnisse auf meinem Rechner (i7, 64-bit, Arch Linux):
[juanlu@nebulae]─[~/Development/Python/test]
└[10:31:10] $ time python pool_multiprocessing.py
real 0m10.330s
user 1m13.430s
sys 0m0.260s
[juanlu@nebulae]─[~/Development/Python/test]
└[10:31:29] $ time python pool_futures.py
real 4m3.939s
user 6m33.297s
sys 0m54.853s
Kann ich nicht Profil diese mit den Python-profiler, weil ich Gurke-Fehler. Irgendwelche Ideen?
- Ich Liebe deine Namenskonvention, vor allem
workers
undhard_work
😛 - Cool, innit? 😛
Du musst angemeldet sein, um einen Kommentar abzugeben.
Bei der Verwendung
map
ausconcurrent.futures
jedes element aus der iterierbar eingereicht separat an den Anbieter, wodurch eineFuture
- Objekt für jeden Aufruf. Es gibt dann ein iterator, welches die Ergebnisse aus den futures.Zukunft
Objekte sind eher im Schwergewicht, Sie tun eine Menge Arbeit zu ermöglichen, alle Funktionen, die Sie bieten (wie z.B. callbacks, die Möglichkeit zu stornieren, status, ...).Verglichen
multiprocessing.Pool
hat viel weniger overhead. Es unterwirft jobs in batches (Reduzierung der IPC overhead), und direkt benutzt das Ergebnis von der Funktion zurückgegeben wird. Für große Chargen von Arbeitsplätzen, multiprocessing ist definitiv die besseren Optionen.Futures sind groß, wenn Sie möchten, füllen Sie lang laufende jobs, bei denen der overhead ist nicht so wichtig, wo Sie benachrichtigt werden möchten, durch Rückruf oder überprüfen Sie von Zeit zu Zeit um zu sehen, ob Sie fertig sind oder in der Lage sein, um das Abbrechen der Ausführung individuell.
Persönliche note:
Kann ich nicht wirklich glaube, sehr viel Gründe für die Verwendung
Executor.map
- es nicht geben Ihnen keine der Funktionen von futures - außer für die Fähigkeit zu geben einen timeout. Wenn Sie nur daran interessiert, die Ergebnisse, sind Sie besser dran mit einem dermultiprocessing.Pool
's map-Funktionen.ProcessPoolExecutor.map
akzeptierenchunksize
Schlüsselwort-argument, das zur Linderung der IPC-overhead-Problem etwas. Finden Sie diese bug für mehr info.ProcessPoolExecutor.map()
wegen dieser bug inmp.Pool.map()