В Python безопасен ли поток/процесс list(queue.queue)?

Насколько я понимаю, внутренние объекты Queue в Python обрабатывают блокировку, поэтому вам не нужно использовать внешние блокировки только для вызова .put() или .get(). Мой вопрос: покрыт ли я теми же внутренними объектами, если я хочу отобразить содержимое очереди, представив его в виде списка через список (очередь) list(queue.queue)? Или, в более общем плане, существует ли какая-либо мыслимая операция с использованием очередей Python, которая требует использования внешних по отношению к объекту очереди блокировок для обеспечения безопасности потоков?

Пример:

from queue import Queue
queue = Queue()
list(queue.queue)

Другими словами, придется ли мне когда-нибудь использовать

with lock_object:
    some_function(queue)

???

🤔 А знаете ли вы, что...
Python является интерпретируемым языком программирования.


61
1

Ответ:

Решено

Непонятно, что вы подразумеваете под словом «очередь». Единственные две стандартные реализации Queue, о которых я знаю, не могут быть перебраны, поэтому «приведение в виде списка» просто вызывает исключение:

>>> import queue
>>> q = queue.Queue()
>>> list(q)
Traceback (most recent call last):
    ...
TypeError: 'Queue' object is not iterable

>>> from multiprocessing import Queue
>>> q = Queue()
>>> list(q)
Traceback (most recent call last):
    ...
TypeError: 'Queue' object is not ierable

Возможно, вам когда-нибудь понадобится сделать:

with lock_object:
    some_function(queue)

на основании того, что вы сказали до сих пор, ответить невозможно. Если, например, ваша логика более высокого уровня основана на переводе очереди в (фактически) режим «только для чтения» на некоторое время, тогда, конечно. Вам понадобится блокировка, чтобы обеспечить взаимное исключение между сторонами чтения и записи на время.

.put() и .get() сами по себе уже безопасны для потоков и процессов (в случае multiprocessing.Queue).

Документация не гарантирует больше, чем просто это, поэтому на него нельзя положиться, даже если это «кажется» работает (что, если это так, может быть надежным несчастным случаем конкретной реализации Python, которую вы используете, или может быть непостоянная авария из-за того, что вы просто еще не столкнулись с соответствующими условиями гонки).

НОВЫЙ ВОПРОС, НОВЫЙ ОТВЕТ

Вопрос был отредактирован, чтобы вместо этого спросить о list(queue.queue). Это подпадает под более раннюю «несчастность конкретной реализации Python, которую вы используете» в двух отношениях:

  1. Не документировано, что объект Queue.queue имеет атрибут queue. Python — это язык «с согласия взрослых», и он не пытается помешать вам использовать детали реализации. Но если вы это сделаете, вы сами по себе. Реализация может измениться в любой момент.
  2. Так получилось, что list(deque) сегодня является потокобезопасным (CPython 3.12.5), но это тоже не документировано. Я знаю это только потому, что смотрел на код реализации C. В версии 3.12.6 это может быть небезопасно для потоков. В более общем плане CPython движется к режиму работы «без GIL», в котором подобные вещи с гораздо большей вероятностью будут страдать от гонок.

Суть не меняется: .put() и .get() сами по себе уже безопасны для потоков и процессов (в случае multiprocessing.Queue). Ничего большего не гарантируется. Действительно! ;-) Ничего. Если вам нужно нечто большее, чтобы обеспечить надежность в различных реализациях и выпусках, вам потребуется предоставить свои собственные блокировки.