Python: Управление очередью Queue.Empty
После коротких дискуссий с кем-то об обработке исключений в 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: Нам было неизвестно, что объект очереди был потокобезопасным. Похоже, что try/except - это путь!
Ответы
Ответ 1
Метод 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" здесь, чтобы сузить область действия предложения исключения.
Ответ 2
Если это многопоточный/многопроцессорный код (так или иначе, это хорошая причина для использования очередей), то определенно метод 1. Между вызовом q.empty()
и вызовом q.get()
Джек Сердца мог украсть ваши пироги!
Ответ 3
Один аргумент заключается в том, что метод 1 неверен, поскольку пустая очередь не является ошибкой и поэтому не должна обрабатываться с использованием исключения Queue.Empty
Исключение не обязательно является "ошибкой", это общий механизм управления потоком и действительно используется в нескольких случаях (SysExit, StopIteration и т.д.).
Хороший вопрос: какой будет самый распространенный случай - пустая или непустая очередь. Если вы точно не знаете, вы хотите, чтобы AskBeforeYouLeap, потому что это очень вероятно дешевле.