Python:Queue.Empty 异常处理
问题描述
在与某人就 Python 中的异常处理(由处理队列对象引发)进行了简短的辩论之后,我想我应该把它扔在那里...
After a short debate with someone about exception handling in Python - sparked by the handling of a queue object - I thought I'd throw it out there...
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()
方法二:
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 异常处理.此外,如果您考虑到任务处理部分可能很大,则使用这种编码方式可能会使调试变得更加困难.
One argument is that Method 1 is wrong because the queue being empty is not an error, and therefore should not be handled using Queue.Empty exception. Additionally, it could make debugging more difficult when coded this way if you consider that the task handling part could potentially large.
另一个论点是,任何一种方式在 Python 中都是可以接受的,如果任务处理量很大,那么在 try/except 之外处理任务可以帮助调试,尽管同意这可能比使用方法 2 看起来更丑.
The other argument is that either way is acceptable in Python and that handling the task outside of the try/except could aid debugging if task handling is large, although agreed that this might look uglier than using Method 2.
意见?
更新:回答 1 后的更多信息......争论是在方法 1 在一些多线程代码中使用之后开始的.在这种情况下,代码将获取锁(从 threading.Lock 对象)并在它返回的任务或 Queue.Empty 被抛出后释放它
UPDATE: A little more info after answer 1 came through.... The debate was started after method 1 was using in some multithreaded code. In which case, the code will acquire the lock (from a threading.Lock object) and release it either once the task it returned or Queue.Empty is thrown
更新 2:我们俩都不知道队列对象是线程安全的.看起来 try/except 是要走的路!
UPDATE 2: It was unknown to both of us that the the queue object was thread safe. Looks like try/except is the way to go!
解决方案
方法 2 是错误的,因为您分两步进行操作,而可以一步完成.在方法 2 中,您检查队列是否为空,然后稍后(很快,但更晚),尝试获取该项目.如果您有两个线程从队列中拉取项目怎么办?get() 仍然可能因队列为空而失败.如果在您检查项目为空后将其添加到队列中怎么办?这些是错误潜入并发代码的微小机会之窗.
Method 2 is wrong because you are doing an operation in two steps when it could be done in one. In method 2, you check if the queue is empty, and then later (very soon, but still later), try to get the item. What if you have two threads pulling items from the queue? The get() could still fail with an empty queue. What if an item is added to the queue after you checked that it was empty? These are the sort of tiny windows of opportunity where bugs creep in to concurrent code.
一步到位,这是迄今为止更好的选择.
Do it in one step, it's by far the better choice.
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"子句来缩小异常子句的范围.
Don't get hung up on "exceptions should be errors". Exceptions are simply another channel of communication, use them. Use the "else" clause here to narrow the scope of the exception clause.
相关文章