2017-02-22 5 views
1

Der Python 3 docs ein Beispiel eines Arbeiter-Thread geben, die eine Warteschlange verwendet (https://docs.python.org/3/library/queue.html):Wann ist Queue.join() notwendig?

def worker(): 
    while True: 
     item = q.get() 
     if item is None: 
      break 
     do_work(item) 
     q.task_done() 

q = queue.Queue() 
threads = [] 
for i in range(num_worker_threads): 
    t = threading.Thread(target=worker) 
    t.start() 
    threads.append(t) 

for item in source(): 
    q.put(item) 

# block until all tasks are done 
q.join() 

# stop workers 
for i in range(num_worker_threads): 
    q.put(None) 
for t in threads: 
    t.join() 

In diesem Beispiel ist, warum q.join() notwendig? Bewirken die nachfolgenden Operationen q.put(None) und t.join() nicht dasselbe, den Hauptthread zu blockieren, bis die Worker-Threads abgeschlossen sind?

Antwort

1

So verstehe ich das Beispiel.

Jeder Arbeiter läuft unendlich, immer auf der Suche nach etwas Neuem aus der Warteschlange. Wenn das Item None bekommt, bricht es ab und gibt die Kontrolle an main zurück.

Also, zuerst lassen wir das Programm warten, bis die Warteschlange leer ist. Jeder Anruf an q.task_done() markiert einen neuen Artikel als abgeschlossen. Der Code hängt am folgenden, so dass wir sicherstellen, dass jedes Element als erledigt markiert ist.

# block until all tasks are done 
q.join() 

Dann unten, fügen wir die gleiche Anzahl von None Elemente in die Warteschlange, wie es Arbeiter sind (so stellen wir sicher, dass jeder Mitarbeiter bekommt man.)

for i in range(num_worker_threads): 
    q.put(None) 

Als nächstes wir kommen alle Fäden. Da wir jedem Arbeiter einen None Gegenstand über die Warteschlange gegeben haben, werden alle kaputt gehen. Bis sie alle brechen und die Kontrolle zurückgeben, wollen wir hier hängen.

for t in threads: 
    t.join() 

es auf diese Weise tut, stellen wir sicher, dass jedes Element in der Warteschlange wird jeder Arbeitnehmer behandelt wird bricht, wenn die Warteschlange leer ist, und jeder Arbeiter herunterfahren, bevor wir mit unserem Code weitergehen, Waise helfen vermeiden Prozesse.

+0

Das ist so, wie ich das Beispiel auch interpretiert habe. Also, meine Frage ist, wird nicht jedes Element in der Warteschlange behandelt (und alle Threads aufgeräumt), selbst wenn wir die Anweisung 'q.join()' entfernen? Wenn wir allen Worker-Threads beitreten (der letzte Schritt), warten wir immer noch darauf, dass alle Elemente in der Warteschlange behandelt werden. – SMX

+1

Ja, wir warten immer noch, aber ich denke, es ist eine codierte Sicherheitsmaßnahme. Was, wenn die Zugabe von "None" auf wundersame Weise hinzugefügt wurde, bevor alle Gegenstände in der Warteschlange bearbeitet wurden und ein Arbeiter einen bekam? Ich denke, es ist nur ein mühsam programmiertes Beispiel, um sicherzustellen, dass Sie verstehen, was passiert, ohne dass Sie vollständig verstehen müssen, dass die Warteschlange FIFO (First In, First Out) ist. Außerdem könnte dieses Beispiel für eine LIFO-Implementierung (Last In, First Out) angepasst werden. Aber mit diesem aktuellen Beispiel glaube ich, dass Sie 'q.join()' rausnehmen könnten und es wäre in Ordnung. – jarcobi889