Вопрос по exception-handling, python, queue – Python: Queue.Empty Exception Handling

16

После короткой дискуссии с кем-то об обработке исключений в Python, вызванной обработкой объекта очереди, я подумал, что я его выброшу ...

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

Один из аргументов заключается в том, что метод 1 неверен, поскольку пустая очередь не является ошибкой и поэтому не должна обрабатываться с использованием исключения Queue.Empty. Кроме того, это может усложнить отладку при кодировании таким образом, если учесть, что часть обработки задач может быть потенциально большой.

Другой аргумент заключается в том, что любой из этих способов приемлем в Python, и что обработка задачи за пределами try / кроме может помочь в отладке, если обработка задачи велика, хотя было решено, что это может выглядеть уродливее, чем при использовании метода 2.

Мнения?

ОБНОВЛЕНИЕ: немного больше информации после того, как ответ 1 прошел .... Дискуссия началась после того, как метод 1 использовался в многопоточном коде. В этом случае код получит блокировку (из объекта threading.Lock) и освободит ее либо после того, как будет возвращено задание, либо будет выдан Queue.Empty.

ОБНОВЛЕНИЕ 2: нам обоим было неизвестно, что объект очереди был потокобезопасным. Похоже, попробуйте / кроме это путь!

Я не вижу, как блокировка меняет ответ, я также не понимаю, зачем нужна блокировка, очередь уже поточно-ориентирована. Ned Batchelder

Ваш Ответ

3   ответа
3

Если это многопоточный / многопроцессорный код (в любом случае это хорошая причина для использования очередей), то, безусловно, метод 1. Междуq.empty() вызов иq.get() зови, Валет Червей мог украсть твои пироги!

Дискуссия началась после того, как метод 1 использовался в многопоточном коде. В этом случае код получит блокировку (из объекта threading.Lock) и освободит ее либо после того, как будет возвращена задача, либо в очередь Queue.Empty ...... того же мнения? user1014903
сохранить код обработки ошибок как можно более строгим - вызовget и сразу после этого проверь ошибку. не нужно встраивать остальную часть кода в попытку ...
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()

Не зацикливайтесь на «исключениях должны быть ошибки». Исключения - это просто еще один канал связи, используйте их. Используйте & quot; еще & quot; здесь, чтобы сузить сферу действия исключения.

2

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

Исключение не обязательно является «ошибкой», оно представляет собой общий механизм управления потоком и действительно используется таким образом в нескольких случаях (SysExit, StopItered и т. Д.).

Хороший вопрос здесь: что будет наиболее распространенным случаем - пустая или непустая очередь. Если вы не знаете наверняка, вы хотите спроситьBeforeYouLeap, потому что это, вероятно, намного дешевле.

Похожие вопросы