Das Endziel besteht darin, eine Methode im Hintergrund auszuführen, aber nicht parallel: Wenn mehrere Objekte diese Methode aufrufen, sollte jeder warten, bis er an der Reihe ist. Um das Ausführen im Hintergrund zu erreichen, muss ich die Methode in einem Unterprozess (kein Thread) ausführen, und ich muss es mit spawn (nicht fork) starten. Um parallele Ausführungen zu verhindern, besteht die offensichtliche Lösung darin, eine globale Sperre zwischen den Prozessen zu verwenden.
Wenn Prozesse gegabelt werden, was bei Unix der Standard ist, ist es einfach zu erreichen, wie in den beiden folgenden Codes hervorgehoben.
Wir können es als Klassenvariable teilen:Python: Freigeben einer Sperre zwischen erzeugten Prozessen
import multiprocessing as mp
from time import sleep
class OneAtATime:
l = mp.Lock()
def f(self):
with self.l:
sleep(1)
print("Hello")
if __name__ == "__main__":
a = OneAtATime()
b = OneAtATime()
p1 = mp.Process(target = a.f)
p2 = mp.Process(target = b.f)
p1.start()
p2.start()
Oder wir können es an die Methode übergeben:
import multiprocessing as mp
from time import sleep
class OneAtATime:
def f(self, l):
with l:
sleep(1)
print("Hello")
if __name__ == "__main__":
a = OneAtATime()
b = OneAtATime()
m = mp.Manager()
l = mp.Lock()
p1 = mp.Process(target = a.f, args = (l,))
p2 = mp.Process(target = b.f, args = (l,))
p1.start()
p2.start()
Beide Codes das entsprechende Verhalten von Druck „Hallo“ auf eine Sekunde haben von Intervall. Wenn Sie jedoch die start method auf "spawn" ändern, werden sie beschädigt.
Der erste (1) druckt beide "hallo" s gleichzeitig. Dies liegt daran, the internal state of a class is not pickled, so dass sie nicht die gleiche Sperre haben.
Die zweite (2) schlägt mit FileNotFoundError zur Laufzeit fehl. Ich denke, es hat damit zu tun, dass Schlösser nicht gebeizt werden können: siehe Python sharing a lock between processes.
In dieser Antwort werden zwei Fixes vorgeschlagen (Randnotiz: Ich kann keinen Pool verwenden, weil ich willkürlich eine beliebige Anzahl von Prozessen erstellen möchte).
import multiprocessing as mp
from time import sleep
if __name__ == "__main__":
mp.set_start_method('spawn')
class OneAtATime:
def f(self, l):
with l:
sleep(1)
print("Hello")
if __name__ == "__main__":
a = OneAtATime()
b = OneAtATime()
m = mp.Manager()
l = m.Lock()
p1 = mp.Process(target = a.f, args = (l,))
p2 = mp.Process(target = b.f, args = (l,))
p1.start()
p2.start()
Dies schlägt mit Attribute und FileNotFoundError (3):
Ich habe keine Möglichkeit zur Anpassung der zweite Lösung, aber ich versuchte, zu implementieren, um den ersten gefunden. Tatsächlich schlägt es auch fehl (BrokenPipe), wenn die Fork-Methode verwendet wird (4).
Was ist die richtige Art, eine Sperre zwischen erzeugten Prozessen zu teilen?
Eine kurze Erklärung der vier Fehler, die ich nummeriert habe, wäre auch nett. Ich führe Python 3.6 unter Archlinux.
Es klingt, als ob Sie die Dokumentation ziemlich sorgfältig gelesen haben. Haben Sie sich die Lösungen in [17.2.1.5] (https://docs.python.org/3.6/library/multiprocessing.html#sharing-state-between-processes) angesehen? Sie sollten in der Lage sein, das Schloss in den gemeinsamen Speicher oder einen Manager zu stecken, richtig? –
Ich habe versucht, es ist in der dritten Code-Snippet. Es hat nicht funktioniert, aber es gibt wahrscheinlich viele Möglichkeiten, dies zu tun, einschließlich eines, das den Trick macht. – Zil0
Entschuldigung, ich hätte den Code vor dem Kommentieren weiter studieren sollen. :-) –