Was ist der Unterschied zwischen python's multiprocessing und concurrent.futures?

8

Eine einfache Methode zum Implementieren von Multiprocessing in Python ist

%Vor%

Eine alternative Implementierung basierend auf Futures ist

%Vor%

Beide Alternativen machen im Wesentlichen dasselbe, aber ein auffälliger Unterschied ist, dass wir den Code nicht mit der üblichen if __name__ == '__main__' -Klausel schützen müssen. Liegt das daran, dass sich die Umsetzung von Futures um diesen oder uns dort einen anderen Grund kümmert?

Im weiteren Sinne, was sind die Unterschiede zwischen multiprocessing und concurrent.futures ? Wann ist man gegenüber dem anderen bevorzugt?

BEARBEITEN: Meine ursprüngliche Annahme, dass der Guard if __name__ == '__main__' nur für Multiprocessing notwendig ist, war falsch. Offensichtlich benötigt man diesen Guard für beide Implementierungen unter Windows, während dies auf Unix-Systemen nicht notwendig ist.

    
David Zwicker 22.07.2014, 19:32
quelle

2 Antworten

16

Sie sollten den if __name__ == "__main__" -Wächter auch mit ProcessPoolExecutor verwenden: Er verwendet multiprocessing.Process , um Pool unter den Deckblättern zu füllen, genau wie multiprocessing.Pool , also alle die gleichen Vorbehalte bezüglich der Pickelfähigkeit (besonders unter Windows), usw. anwenden.

Ich glaube, dass ProcessPoolExecutor laut dieser Aussage von Jesse Noller letztendlich multiprocessing.Pool ersetzen soll (ein Python-Core-Contributor), wenn man fragt, warum Python beide APIs hat:

  

Brian und ich müssen an der geplanten Konsolidierung arbeiten   da sich die Leute mit den APIs vertraut gemacht haben. Mein eventuelles Ziel ist es, zu entfernen   alles andere als das grundlegende Multiprocessing.Process / Queue Zeug aus MP   und in concurrent. * und unterstützen Threading-Backends dafür.

Momentan macht ProcessPoolExecutor genau dasselbe wie multiprocessing.Pool mit einer einfacheren (und begrenzteren) API. Wenn Sie ProcessPoolExecutor verwenden können, verwenden Sie das, weil ich denke, dass es auf lange Sicht eher zu Verbesserungen kommt.

Beachten Sie, dass Sie alle Helfer von multiprocessing mit ProcessPoolExecutor , wie Lock , Queue , Manager usw. verwenden können. Die Hauptgründe für die Verwendung von multiprocessing.Pool sind, wenn Sie initializer benötigen. / initargs (es gibt jedoch einen offenen Fehler , um diese zu ProcessPoolExecutor hinzuzufügen) oder maxtasksperchild . Oder Sie führen Python 2.7 oder früher aus und möchten den Backport von concurrent.futures nicht installieren (oder von Ihren Benutzern installieren).

Bearbeiten:

Bemerkenswert: Laut dieser Frage übertrifft multiprocessing.Pool.map ProcessPoolExecutor.map . Beachten Sie, dass der Leistungsunterschied sehr gering ist pro Arbeitselement . Sie werden daher wahrscheinlich nur dann einen großen Leistungsunterschied bemerken, wenn Sie map auf einem sehr großen iterierbaren Wert verwenden. Der Grund für den Leistungsunterschied ist, dass multiprocessing.Pool das iterable, das übergeben wurde, in Chunks stapelweise verarbeitet und dann die Chunks an die Worker-Prozesse weiterleitet, was den Overhead von IPC zwischen dem Eltern- und dem Child-Objekt reduziert. ProcessPoolExecutor übergibt immer ein Element von dem iterablen Element zu einem Zeitpunkt an die untergeordneten Elemente, was aufgrund des erhöhten IPC-Overheads zu einer viel langsameren Leistung mit großen Iterablen führen kann. Die gute Nachricht ist, dass dieses Problem in Python 3.5 behoben wird, da chunksize Schlüsselwort-Argument zu ProcessPoolExecutor.map hinzugefügt wurde, das verwendet werden kann, um eine größere Chunk-Größe anzugeben, wenn Sie mit großen Iterablen arbeiten. Weitere Informationen finden Sie in diesem Fehler .

    
dano 22.07.2014, 19:40
quelle
3

if __name__ == '__main__': bedeutet nur, dass Sie das Skript an der Eingabeaufforderung mit python <scriptname.py> [options] anstelle von import <scriptname> in der Python-Shell aufgerufen haben.

Wenn Sie ein Skript von der Eingabeaufforderung aus aufrufen, wird die Methode __main__ aufgerufen. Im zweiten Block das

%Vor% Der

-Block wird unabhängig davon ausgeführt, ob er von der Eingabeaufforderung aus aufgerufen oder von der Shell importiert wurde.

    
user2867522 22.07.2014 19:37
quelle