8 Stimmen

Das Anhängen eines Prozesses an eine Liste (ohne etwas damit zu tun) ändert das Programmverhalten

Wenn ich im folgenden Programm den Prozess an eine Liste anhänge (was scheinbar sinnlos ist), läuft er wie erwartet. Entferne ich jedoch das Anhängen, wird der Destruktor des Prozesses viele Male aufgerufen, bevor er überhaupt ausgeführt wird. Es gibt nur n Konstruktionen, sondern (n)(n+1)/2 (wobei n ist die Anzahl der Prozesse) Zerstörungen. Dies führt mich zu der Annahme, dass jeder Prozess in jeden neuen Prozess kopiert und dann sofort zerstört wird. Vielleicht funktioniert das Multiprocessing-Modul so. Das macht Sinn, da jeder Prozess eine Abspaltung des aktuellen Prozesses ist. Aber welche Bedeutung hat das Anhängen an die Liste? Warum wird dieses Verhalten dadurch gestoppt?

Hier sind der Test und die Beispielausgabe:

import multiprocessing

class _ProcSTOP:
    pass

class Proc(multiprocessing.Process):

    def __init__(self, q, s): 
        s.i += 1
        self._i = s.i 
        self._q = q 
        print('constructing:', s.i)
        super().__init__()

    def run(self):
        dat = self._q.get()

        while not dat is _ProcSTOP:
            self._q.task_done()
            dat = self._q.get()

        self._q.task_done()
        print('returning:   ', self._i)

    def __del__(self):
        print('destroying:  ', self._i)

if __name__ == '__main__':

    q = multiprocessing.JoinableQueue()
    s = multiprocessing.Manager().Namespace()
    s.i = 0 
    pool = []

    for i in range(4):
        p = Proc(q, s)
        p.start()
        pool.append(p)    # This is the line to comment

    for i in range(10000):
        q.put(i)

    q.join()

    for i in range(4):
        q.put(_ProcSTOP)

    q.join()

    print('== complete')

Beispielhafte Ausgabe mit Anhängen:

constructing: 1
constructing: 2
constructing: 3
constructing: 4
returning:    3
returning:    2
== complete
returning:    1
returning:    4
destroying:   4
destroying:   3
destroying:   2
destroying:   1

Beispielhafte Ausgabe ohne Anhängen:

constructing: 1
constructing: 2
constructing: 3
destroying:   1
constructing: 4
destroying:   1
destroying:   2
destroying:   3
destroying:   1
destroying:   2
returning:    1
returning:    4
returning:    2
== complete
returning:    3
destroying:   1
destroying:   3
destroying:   2
destroying:   4

1voto

Mihai Stan Punkte 1032

Das Hinzufügen des Objekts zu einer Liste verhindert, dass es in untergeordneten Prozessen gelöscht wird, da es nach dem Forking "os._exit()" aufruft, anstatt den gesamten Stapel zu leeren

Der entsprechende Code befindet sich in multiprocessing/forking.py (Konstruktor von Popen, der bei "p.start()" aufgerufen wird)

 self.pid = os.fork()
 if self.pid == 0:
     if 'random' in sys.modules:
         import random
         random.seed()
     code = process_obj._bootstrap()
     sys.stdout.flush()
     sys.stderr.flush()
     os._exit(code)

Wo _bootstrap den neuen Prozess einrichtet und "run" aufruft (der Code ist in multiprocessing/process.py)

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X