Python:Queue.Empty异常处理

时间:2012-06-28 15:00:28

标签: python exception-handling queue

与某人就Python中的异常处理进行了短暂的辩论 - 由处理队列对象引发 - 我以为我会把它扔出去......

方法1:

import Queue

q = Queue.Queue()

try:
    task=q.get(False)
    #Opt 1: Handle task here and call q.task_done()
except Queue.Empty:
    #Handle empty queue here
    pass

#Opt2: Handle task here and call q.task_done()

方法2:

import Queue

q = Queue.Queue()

if q.empty():
    #Handle empty queue here
else:
    task = q.get()
    #Handle task here
    q.task_done()

一个参数是方法1是错误的,因为队列为空不是错误,因此不应使用Queue.Empty异常处理。此外,如果您认为任务处理部分可能很大,则以这种方式编码会使调试更加困难。

另一个论点是,在Python中可以接受任何一种方式,并且在任务处理很大的情况下处理try / except之外的任务可以帮助调试,尽管同意这可能看起来比使用方法2更糟糕。

评论

更新:在回答1之后再​​多一点信息.... 在方法1在一些多线程代码中使用之后,争论就开始了。在这种情况下,代码将获取锁(来自threading.Lock对象)并在其返回的任务或抛出Queue.Empty时释放它

更新2:我们俩都不知道队列对象是线程安全的。看起来像尝试/除了是要走的路!

3 个答案:

答案 0 :(得分:31)

方法2是错误的,因为当您可以在一个步骤中完成操作时,您将分两步执行操作。在方法2中,您检查队列是否为空,然后(很快,但仍然更晚),尝试获取该项目。如果你有两个线程从队列中拉出项目怎么办? get()仍然可能因空队列而失败。如果在检查项目为空之后将项目添加到队列中会怎样?这些是一些微小的机会窗口,其中错误蔓延到并发代码。

一步到位,这是目前为止更好的选择。

import Queue

q = Queue.Queue()

try:
    task = q.get(False)
except Queue.Empty:
    # Handle empty queue here
    pass
else:
    # Handle task here and call q.task_done()

不要挂断“异常应该是错误”。例外只是另一种沟通渠道,使用它们。在这里使用“else”子句来缩小异常子句的范围。

答案 1 :(得分:3)

如果这是多线程/多处理代码(无论如何都是使用队列的一个很好的理由),那么肯定方法1.在q.empty()通话和q.get()通话之间,Jack of Hearts可以拥有偷了你的馅饼!

答案 2 :(得分:2)

  

一个参数是方法1是错误的,因为队列为空不是错误,因此不应使用Queue.Empty异常处理

异常不一定是“错误”,它是一种通用的流控制机制,并且在少数情况下确实以这种方式使用(SysExit,StopIteration等)。

这里的好问题是:最常见的情况是什么 - 空队列或非空队列。除非你确定,否则你想要AskBeforeYouLeap,因为它可能更便宜。