it-swarm.com.de

python Multiprocessing - Prozess hängt beim Join für große Warteschlange ab

Ich arbeite mit Python 2.7.3 und mir ist folgendes merkwürdiges Verhalten aufgefallen. Betrachten Sie dieses minimale Beispiel:

from multiprocessing import Process, Queue

def foo(qin, qout):
    while True:
        bar = qin.get()
        if bar is None:
            break
        qout.put({'bar': bar})

if __== '__main__':
    import sys

    qin = Queue()
    qout = Queue()
    worker = Process(target=foo,args=(qin,qout))
    worker.start()

    for i in range(100000):
        print i
        sys.stdout.flush()
        qin.put(i**2)

    qin.put(None)
    worker.join()

Wenn ich eine Schleife über 10.000 oder mehr durchgehe, hängt mein Skript an worker.join(). Es funktioniert gut, wenn die Schleife nur auf 1.000 geht.

Irgendwelche Ideen?

20
user545424

Die qout-Warteschlange im Unterprozess wird voll. Die von foo() eingegebenen Daten passen nicht in den Puffer der intern verwendeten Pipes des Betriebssystems. Daher blockiert der Unterprozess den Versuch, mehr Daten einzupassen. Der übergeordnete Prozess liest diese Daten jedoch nicht: er wird einfach gesperrt und wartet, bis der Unterprozess abgeschlossen ist. Dies ist ein typischer Deadlock.

28
Armin Rigo

Die Größe der Warteschlangen muss begrenzt sein. Betrachten Sie die folgende Änderung:

from multiprocessing import Process, Queue

def foo(qin,qout):
    while True:
        bar = qin.get()
        if bar is None:
            break
        #qout.put({'bar':bar})

if __name__=='__main__':
    import sys

    qin=Queue()
    qout=Queue()   ## POSITION 1
    for i in range(100):
        #qout=Queue()   ## POSITION 2
        worker=Process(target=foo,args=(qin,))
        worker.start()
        for j in range(1000):
            x=i*100+j
            print x
            sys.stdout.flush()
            qin.put(x**2)

        qin.put(None)
        worker.join()

    print 'Done!'

Dies funktioniert wie es ist (mit qout.put Zeile auskommentiert). Wenn Sie versuchen, alle 100000 Ergebnisse zu speichern, wird qout zu groß: Wenn ich die qout.put({'bar':bar}) in foo auskommentiere und die Definition von qout in POSITION 1 belasse, bleibt der Code hängen. Wenn ich jedoch die qout-Definition in POSITION 2 versetze, wird das Skript beendet.

Kurz gesagt, Sie müssen darauf achten, dass weder qin noch qout zu groß werden. (Siehe auch: Maxsize Limit für Multiprocessing Queue ist 32767 )

3
amd

Ich hatte das gleiche Problem mit python3, als ich versuchte, Zeichenketten in eine Warteschlange mit einer Gesamtgröße von etwa 5000 cahrs zu bringen.

In meinem Projekt gab es einen Host-Prozess, der eine Warteschlange einrichtet, einen Unterprozess startet und dann beitritt. Afrer join Der Host-Prozess liest die Warteschlange. Wenn der Unterprozess zu viele Daten produziert, wird auf join gesetzt. Ich habe dies mit der folgenden Funktion behoben, um auf den Unterprozess im Host-Prozess zu warten:

def yield_from_process(q, p):
    while p.is_alive():
        p.join(timeout=1)
        while True:
            try:
                yield q.get(block=False)
            except Empty:
                break

Ich lese aus der Warteschlange, sobald es gefüllt ist, damit es nie sehr groß wird

3
Rugnar

Ich habe versucht, einen asynchronen Arbeiter zu .get(), nachdem der Pool geschlossen wurde

einrückungsfehler außerhalb eines mit Block

ich hatte das

with multiprocessing.Pool() as pool:
    async_results = list()
    for job in jobs:
        async_results.append(
            pool.apply_async(
                _worker_func,
                (job,),
            )
        )
# wrong
for async_result in async_results:
    yield async_result.get()

ich brauchte das

with multiprocessing.Pool() as pool:
    async_results = list()
    for job in jobs:
        async_results.append(
            pool.apply_async(
                _worker_func,
                (job,),
            )
        )
    # right
    for async_result in async_results:
        yield async_result.get()
0
ThorSummoner