2014-08-28 11 views
25

Ich versuche, eine partielle Funktion zu verwenden, so dass pool.map() eine Funktion mit mehr als einem Parameter (in diesem Fall ein Lock() Objekt) zielen kann. HierPython sharing eine Sperre zwischen Prozessen

ist Codebeispiel (aus einer Antwort auf eine frühere Anfrage von mir):

from functools import partial 

def target(lock, iterable_item): 
    for item in items: 
     # Do cool stuff 
     if (... some condition here ...): 
      lock.acquire() 
      # Write to stdout or logfile, etc. 
      lock.release() 

def main(): 
    iterable = [1, 2, 3, 4, 5] 
    pool = multiprocessing.Pool() 
    l = multiprocessing.Lock() 
    func = partial(target, l) 
    pool.map(func, iterable) 
    pool.close() 
    pool.join() 

Jedoch, wenn ich diesen Code ausführen, erhalte ich die Fehlermeldung:

Runtime Error: Lock objects should only be shared between processes through inheritance. 

Was bin ich hier fehlt? Wie kann ich die Sperre zwischen meinen Teilprozessen teilen?

+0

Es gibt eine andere Frage zu demselben Problem, obwohl ihr bestimmter Fehler anders ist - [Probleme bei der Verwendung einer Sperre mit Multiprocessing.Pool: Beizfehler] (http://stackoverflow.com/questions/17960296/trouble-usinga-a- Lock-with-Multiprocessing-Pool-Beizen-Fehler) –

Antwort

46

Entschuldigung, ich hätte dies in meiner Antwort auf Ihre andere Frage erwischt. Sie können normale multiprocessing.Lock Objekte nicht an Methoden Pool übergeben, da sie nicht gebeizt werden können. Es gibt zwei Möglichkeiten, dies zu umgehen. Eine davon ist Manager() zu erstellen und übergibt ein Manager.Lock():

def main(): 
    iterable = [1, 2, 3, 4, 5] 
    pool = multiprocessing.Pool() 
    m = multiprocessing.Manager() 
    l = m.Lock() 
    func = partial(target, l) 
    pool.map(func, iterable) 
    pool.close() 
    pool.join() 

Dies ist ein bisschen Schwergewicht, obwohl; Bei Verwendung von Manager muss ein anderer Prozess zum Hosten des Servers Manager gestartet werden. Und alle Anrufe an acquire/release das Schloss müssen zu diesem Server über IPC gesendet werden.

Die andere Option besteht darin, die reguläre multiprocessing.Lock() zur Zeit der Poolerstellung zu übergeben, mit dem initializer Kwarg. Dies wird Ihre Sperre Instanz global in allen Kinderarbeiter machen:

def target(iterable_item): 
    for item in items: 
     # Do cool stuff 
     if (... some condition here ...): 
      lock.acquire() 
      # Write to stdout or logfile, etc. 
      lock.release() 
def init(l): 
    global lock 
    lock = l 

def main(): 
    iterable = [1, 2, 3, 4, 5] 
    l = multiprocessing.Lock() 
    pool = multiprocessing.Pool(initializer=init, initargs=(l,)) 
    pool.map(target, iterable) 
    pool.close() 
    pool.join() 

Die zweite Lösung hat den Nebeneffekt, nicht mehr erforderlich partial.

+0

Nun, vielen Dank noch einmal, mein Herr. Das sieht genau so aus, wie ich es brauche. Ich schätze die fortgesetzte Hilfe! Andere Optionen sahen super involviert aus. Ich werde mit der Initialisiererfunktion gehen, um die globale Sperre zu teilen. – DJMcCarthy12

+0

Das hat super funktioniert. Ich habe auch eine 'Queue' in die init eingefügt, um die Weitergabe in jedem Aufruf zu speichern. – fantabolous

+1

@dano Vielen Dank für Ihre Antwort, ich hatte auch die gleiche Abfrage und diese löst es perfekt, jedoch habe ich eine andere Frage, warum dieser Ansatz nicht häufig verwendet wird, um Status zwischen Prozessen zu teilen, anstatt dies über ein Manager-Objekt zu tun hat einen eigenen Overhead für die Ausführung von Serverprozessen und Proxyzugriff? – bawejakunal

Verwandte Themen