Существует множество различных реализаций очередей производитель-потребитель, например queue.Queue. Обычно они отличаются многими свойствами, перечисленными в этой отличной статье автора Дмитрий Вьюков. Как видите, возможных комбинаций более 10 тысяч. Алгоритмы, используемые для таких очередей, также сильно различаются в зависимости от требований. Невозможно просто расширить существующий алгоритм очереди, чтобы гарантировать дополнительные свойства, поскольку для этого обычно требуются другие внутренние структуры данных и другие алгоритмы.
Каналы Go предлагают относительно большое количество гарантированных свойств, поэтому эти каналы могут подойти для многих программ. Одним из самых сложных требований является поддержка чтения/блокировки на нескольких каналах одновременно (оператор select) и справедливого выбора канала, если более одной ветки в операторе select могут выполняться, чтобы никакие сообщения не оставались позади. . Python queue.Queue не предлагает этих функций, поэтому просто невозможно заархивируйте такое же поведение с ним.
Итак, если вы хотите продолжать использовать queue.Queue, вам нужно найти обходные пути для эта проблема. Однако обходные пути имеют свой собственный список недостатков, и их сложнее поддерживать. Поиск другой очереди производителя-потребителя, которая предлагает необходимые вам функции, может быть лучшей идеей! В любом случае, вот два возможных обходных пути:
Опрос
while True:
try:
i1 = c1.get_nowait()
print "received %s from c1" % i1
except queue.Empty:
pass
try:
i2 = c2.get_nowait()
print "received %s from c2" % i2
except queue.Empty:
pass
time.sleep(0.1)
Это может использовать много циклов ЦП при опросе каналов и может быть медленным при большом количестве сообщений. Использование time.sleep() с экспоненциальным временем задержки (вместо показанных здесь постоянных 0,1 секунды) может значительно улучшить эту версию.
Единая очередь уведомлений
queue_id = notify.get()
if queue_id == 1:
i1 = c1.get()
print "received %s from c1" % i1
elif queue_id == 2:
i2 = c2.get()
print "received %s from c2" % i2
При такой настройке вы должны отправить что-то в очередь уведомлений после отправки на c1 или c2. Это может сработать для вас, если вам достаточно только одной такой очереди уведомлений (т. е. у вас нет нескольких «выборов», каждый из которых блокируется на другом подмножестве ваших каналов).
В качестве альтернативы вы также можете рассмотреть возможность использования Go. Горутины и поддержка параллелизма в Go в любом случае намного мощнее, чем ограниченные возможности потоковой обработки Python.
person
tux21b
schedule
16.12.2011
Queue
, вы хотите использоватьQueue.get()
для каждого из них (что является блокирующим вызовом), и первый разблокирующий вызов — это тот, с которым вы хотите работать? Можете ли вы сказать нам, почему вы не используете только одинQueue
? - person Ethan Furman   schedule 15.12.2011