Search code examples
pythonmultithreadingqueue

In python, is list(queue.queue) thread/process safe?


My understanding is that internals of Queue objects in python handle locking so that that you don't need to use locks externally just to call .put() or .get(). My question is am I covered by those same object internals if I want to display the contents of the queue by casting it as a list via list(queue) list(queue.queue)? Or, more generally, is there any conceivable operation using python queues that require the use of locks external to the queue object to ensure thread safety?

Example:

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

Phrased another way, will I ever have to use

with lock_object:
    some_function(queue)

???


Solution

  • It's unclear what you mean by "Queue". The only two standard Queue implementations I'm aware of cannot be iterated over, so "casting it as a list" just raises an exception:

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

    Whether you may ever need to do:

    with lock_object:
        some_function(queue)
    

    can't be answered based on what you've said so far. If, for example, your higher-level logic relies on putting the queue into (in effect) "read only" mode for some time, then, sure. You'll need a lock to ensure mutual exclusion between the reading and writing sides for the duration.

    .put() and .get() on their own are already thread- and process- (in the case of multiprocessing.Queue) safe.

    More than just that is not guaranteed by the docs, so can't be relied on even if it "appears to" work (which, if so, may be a reliable accident of the specific Python implementation you're using, or may be a fickle accident due to your simply not having yet bumped into a relevant race condition).

    NEW QUESTION, NEW ANSWER

    The question was edited to ask about list(queue.queue) instead. That falls under the earlier "accident of the specific Python implementation you're using", in two respects:

    1. It's not documented that a Queue.queue object has a queue attribute. Python is a "consenting adults" language, and doesn't try to prevent you from using implementation details. But, if you do, you're on your own. The implementation may change at any time.
    2. It so happens that list(deque) is thread-safe today (CPython 3.12.5), but that's not documented either. I only know that it is because I stared at the C implementation code. It may not be thread-safe in 3.12.6. More generally, CPython is moving toward a "no GIL" mode of operation, in which this kind of thing becomes much more likely to suffer races.

    The bottom line doesn't change: .put() and .get() on their own are already thread- and process- (in the case of multiprocessing.Queue) safe. Nothing more than that is guaranteed. Really! ;-) Nothing. If you need more than just that much to be reliable across implementations and releases, you'll need to supply your own locks.