2009-05-04 6 views
10

スレッディングとキューを使用するプログラムを使用している場合、どのようにして実行を停止する例外が発生しますか?ここでは、ctrl-c(基本的にpythonのドキュメントからリッピング)で停止することはできませんプログラムの例です。スレッドとキューを使用しているときに例外を処理するにはどうすればよいですか?

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 

答えて

6

最も簡単な方法は、デーモンスレッドなど、すべてのワーカースレッドを開始することで、その後、ちょうどあなたのメインループにCtrl + Cは、あなたのメインスレッドで例外がスローされます打撃

while True: 
    sleep(1) 

ことがあり、すべてのインタプリタが終了すると、デーモンスレッドの終了が終了します。これは、終了する前にすべてのスレッドでクリーンアップを実行しないことを前提としています。

より複雑な方法は、グローバル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) 

それはKeyboardInterrupt

​​

を取得するときに次に、あなたのメインループは、これはあなたの労働者をすることができますFalsestoppedイベントを設定することができますスレッドは、すべてのワーカースレッドをデーモンにして実行の途中で終了させるのではなく、自分が望んでいることを終わらせます。あなたはどんなクリーンアップをしたいこともできます。

この例ではq.join()を使用していないことに注意してください。これは状況をより複雑にしますが、それでも使用できます。その場合は、例外の代わりにシグナルハンドラを使用してKeyboardInterruptを検出することをお勧めします。例:

これで、メインループが途中にあるものに影響を与えずにCtrl + Cを押したときの動作を定義できます。だから、Ctrl + Cで中断することを心配することなく、q.join()をやり続けることができます。もちろん、私の上記の例では、参加する必要はありませんが、他の理由があるかもしれません。

+1

したがって、基本的にq.join()を使用すると、スレッド内の例外を処理するのが難しくなりますか? –

+1

"シグナル(SIGINT、stop)"を読み込まないといけませんか? – Ber

+0

これは事態をより複雑にしていますが、私はシグナルを使用してq.join()を使用する理由を示した例を追加しました。 –

1

A(おそらく)offtopic注:

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

(あなたがpython3000を使用しない限り)あなたがここに範囲の代わりにはxrangeを使用することができます。あなたはそうすることによっていくつかのCPUとメモリを節約します。 xrangeの詳細はhereです。

関連する問題