python的empty_Python:Queue.Empty异常处理

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...

METHOD 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()

METHOD 2:

import Queue

q = Queue.Queue()

if q.empty():

#Handle empty queue here

else:

task = q.get()

#Handle task here

q.task_done()

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.

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.

Opinions?

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

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!

解决方案

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()

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.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
可以使用 `threading.Event` 代替 `queue.Queue` 来控制线程的结束。`threading.Event` 是一个线程同步的工具,可以让一个或多个线程等待某个事件的发生。具体地,可以创建一个 `Event` 对象,调用 `wait()` 方法等待事件的发生,调用 `set()` 方法通知事件的发生。 下面是一个使用 `Event` 改写后的代码: ```python import queue import threading from concurrent.futures import ThreadPoolExecutor, as_completed def push_data(data_list: list): while data_list: data = data_list.pop() data_queue.put(data) def process_data(data): # 处理数据逻辑 print("Processing data:", data) if __name__ == '__main__': data_queue = queue.Queue() data_list = ["123", "456", "789"] # 创建线程池 with ThreadPoolExecutor(max_workers=5) as executor: # 启动数据生产线程 t = threading.Thread(target=push_data, args=(data_list,)) t.start() # 从队列中获取数据并处理 while True: try: data = data_queue.get(timeout=1) except queue.Empty: if not t.is_alive(): break else: continue # 提交任务到线程池 future = executor.submit(process_data, data) future.add_done_callback(lambda f: f.result()) t.join() ``` 在这个代码中,我们将数据存储在一个普通的列表中,用一个专门的线程 `push_data` 来将数据逐一放入队列中。主线程不断从队列中获取数据并处理,如果队列为空并且 `push_data` 线程已经结束,则主线程也结束。这样就可以避免使用 `Event` 对象了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值