【问题标题】:How do I handle exceptions when using threading and Queue?使用线程和队列时如何处理异常?
【发布时间】:2010-10-23 15:16:14
【问题描述】:

如果我有一个使用线程和队列的程序,我如何获得异常以停止执行?这是一个示例程序,不能用 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

【问题讨论】:

    标签: python multithreading exception


    【解决方案1】:

    最简单的方法是将所有工作线程作为守护线程启动,然后让你的主循环成为

    while True:
        sleep(1)
    

    点击 Ctrl+C 会在你的主线程中抛出一个异常,当解释器退出时,所有的守护线程都会退出。这假设您不想在所有这些线程退出之前对其执行清理。

    更复杂的方法是拥有一个全局的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)
    

    然后你的主循环可以将stopped事件设置为False,当它获得KeyboardInterrupt

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

    这可以让您的工作线程完成您想要的工作,而不是让每个工作线程都成为一个守护进程并在执行过程中退出。你也可以做任何你想做的清理工作。

    请注意,此示例没有使用q.join() - 这会使事情变得更加复杂,尽管您仍然可以使用它。如果你这样做了,那么你最好的选择是使用信号处理程序而不是异常来检测KeyboardInterrupts。例如:

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

    这可以让您定义当您按下 Ctrl+C 时会发生什么,而不会影响您的主循环中间的任何内容。所以你可以继续做q.join(),而不用担心被 Ctrl+C 打断。当然,在我上面的例子中,你不需要加入,但你可能有其他原因加入。

    【讨论】:

    • 那么,基本上,使用 q.join() 很难处理线程中的异常?
    • 它使事情变得更加复杂,但我添加了一个带有信号的示例,向您展示如果您有充分的理由使用 q.join(),您将如何使用它。
    • 感谢您的回答,但似乎当主线程在 Queue.join() 上阻塞时,即使使用上面的处理程序代码 sn-p,它仍然无法获得 SIGNINT。
    • @JJC:我已经编辑了我的答案以使用 threading.Event,所以现在你可以在主线程中使用 Queue.get_nowait,如果你想要一个安全的替代方案,你可以使用 @ 987654334@。希望新的代码示例清晰。
    • @EliCourtwright 我还没有尝试过,但感谢您的更新!
    猜你喜欢
    • 2013-09-10
    • 1970-01-01
    • 1970-01-01
    • 2016-01-17
    • 2013-02-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-05-02
    相关资源
    最近更新 更多