2009-05-04 1 views
10

Wenn ich ein Programm habe, das Threading und Queue verwendet, wie erhalte ich Ausnahmen, um die Ausführung zu stoppen? Hier ist ein Beispielprogramm, das nicht mit ctrl-c beendet werden kann (im Prinzip aus den Python-Dokumenten herausgerissen).Wie gehe ich mit Exceptions um, wenn Threading und Queue verwendet werden?

from threading import Thread 
from Queue import Queue 
from time import sleep 

def do_work(item): 
    sleep(0.5) 
    print "working" , item 

def worker(): 
     while True: 
      item = q.get() 
      do_work(item) 
      q.task_done() 

q = Queue() 

num_worker_threads = 10 

for i in range(num_worker_threads): 
    t = Thread(target=worker) 
    # t.setDaemon(True) 
    t.start() 

for item in range(1, 10000): 
    q.put(item) 

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

Antwort

6

Der einfachste Weg ist es, alle Arbeitsthreads als Daemon-Threads zu starten, dann müssen nur Ihre Hauptschleife

while True: 
    sleep(1) 

Drücken von Strg + C eine Ausnahme in der Haupt-Thread werfen wird, und alle der Daemon-Threads werden beendet, wenn der Interpreter beendet wird. Dies setzt voraus, dass Sie in all diesen Threads keine Bereinigung durchführen möchten, bevor sie beendet werden.

Eine komplexere Art und Weise ist ein haben globale stoppedEvent:

stopped = Event() 
def worker(): 
    while not stopped.is_set(): 
     try: 
      item = q.get_nowait() 
      do_work(item) 
     except Empty:  # import the Empty exception from the Queue module 
      stopped.wait(1) 

dann Ihre Hauptschleife des stopped Event False einstellen kann, wenn sie einen Ihren Arbeiter Auf diese Weise kann KeyboardInterrupt

try: 
    while not stopped.is_set(): 
     stopped.wait(1) 
except KeyboardInterrupt: 
    stopped.set() 

bekommen Die Threads beenden das, was sie tun, anstatt nur jeden Worker-Thread als Daemon zu verwenden und mitten in der Ausführung zu beenden. Sie können auch die Reinigung durchführen, die Sie möchten.

Beachten Sie, dass dieses Beispiel q.join() nicht verwendet - das macht die Dinge komplexer, obwohl Sie es immer noch verwenden können. Wenn Sie das tun, dann sollten Sie Signalhandler anstelle von Ausnahmen verwenden, um KeyboardInterrupt s zu erkennen. Zum Beispiel:

from signal import signal, SIGINT 
def stop(signum, frame): 
    stopped.set() 
signal(SIGINT, stop) 

Auf diese Weise können Sie definieren, was passiert, wenn Sie Strg + C treffen, ohne zu beeinflussen, was auch immer Ihre Hauptschleife in der Mitte ist. So können Sie weiter machen q.join() ohne sich Gedanken über eine Unterbrechung durch eine Strg + C. Natürlich, mit meinen obigen Beispielen, müssen Sie nicht beitreten, aber Sie haben vielleicht einen anderen Grund dafür.

+1

Also, im Grunde macht die Verwendung von q.join() es schwierig, Ausnahmen in den Threads zu behandeln? –

+1

Sollte das "Signal (SIGINT, stop)" nicht gelesen werden? – Ber

+0

Es macht die Dinge komplexer, aber ich habe ein Beispiel mit Signalen hinzugefügt, um Ihnen zu zeigen, wie Sie q.join() verwenden würden, wenn Sie einen guten Grund hätten, dies zu verwenden. –

1

A (möglicherweise) offtopic Anmerkung:

(...) 
for item in range(1, 10000): 
    q.put(item) 
(...) 

Sie könnten xrange statt Bereich hier verwenden (es sei denn, Sie python3000 verwenden). Sie sparen dadurch etwas CPU und Speicher. Mehr zu xrange finden Sie unter here.

Verwandte Themen