Python
queue
collections
data structures
programming

queue.Queue vs. collections.deque

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

Introduction

queue.Queue and collections.deque can both be used in FIFO-style code, but they are not interchangeable abstractions. deque is a fast general-purpose double-ended container, while queue.Queue is a higher-level synchronized queue designed for producer-consumer coordination between threads.

What deque Is Good At

A deque gives efficient appends and pops from both ends.

python
1from collections import deque
2
3items = deque()
4items.append("a")
5items.append("b")
6print(items.popleft())

For single-threaded code or simple buffering logic, it is often the fastest and simplest choice.

It also supports patterns that a plain FIFO queue does not, such as appending on the left, rotating, or using a maximum length.

python
1recent = deque(maxlen=3)
2for value in [1, 2, 3, 4]:
3    recent.append(value)
4print(recent)

What queue.Queue Adds

queue.Queue is about coordination, not just storage. It includes:

  • locking for multi-threaded access
  • optional blocking put and get
  • task tracking with task_done and join
  • optional max size for bounded backpressure
python
1import queue
2import threading
3
4q = queue.Queue()
5
6
7def worker():
8    item = q.get()
9    print("processed", item)
10    q.task_done()
11
12
13threading.Thread(target=worker).start()
14q.put("job-1")
15q.join()

That is much more than a container. It is a thread coordination primitive.

Thread Safety Is The Big Divider

If multiple threads need to hand work to one another safely, queue.Queue is the standard answer. A deque by itself does not provide the same blocking semantics or queue-completion tracking.

In CPython, some individual deque operations are thread-safe at the interpreter level, but that does not make deque a full replacement for a synchronized producer-consumer queue.

Blocking Behavior Changes The Design

queue.Queue.get() can wait until an item is available. deque.popleft() raises an exception if the deque is empty.

python
1from collections import deque
2
3items = deque()
4# items.popleft() would raise IndexError here

If your code needs to sleep until work arrives, queue.Queue fits naturally. If your code wants fast in-memory operations and can handle emptiness directly, deque is often better.

Performance Tradeoff

For raw append and pop throughput, deque is generally lighter because it does not pay the overhead of condition variables and queue bookkeeping.

That is why deque is often used for sliding windows, BFS queues, caches, and local buffering, while queue.Queue is used for thread pools and worker pipelines.

SimpleQueue Is Also Worth Knowing

Python also provides queue.SimpleQueue, which is a simpler synchronized queue without task tracking.

python
1from queue import SimpleQueue
2
3q = SimpleQueue()
4q.put(1)
5print(q.get())

If you need thread-safe FIFO behavior but not task_done and join, it can be a good middle ground.

Choose By Semantics, Not Just By API Similarity

If the program is single-threaded and you only need fast FIFO operations, deque is usually the right tool. If threads need to coordinate around work items, use queue.Queue or SimpleQueue.

The main question is not "which one has append-like behavior." It is "does this code need synchronization and blocking queue semantics?"

Common Pitfalls

The most common mistake is using deque for a threaded producer-consumer system just because append and popleft are fast. Another is using queue.Queue in performance-sensitive single-threaded code where its synchronization overhead buys nothing. Developers also sometimes forget that queue.Queue supports task_done and join, which are important when the program needs to know when all queued work has been processed.

Summary

  • 'deque is a fast general-purpose double-ended container.'
  • 'queue.Queue is a synchronized queue for multi-threaded coordination.'
  • Use deque for local buffering and single-threaded FIFO behavior.
  • Use queue.Queue when you need blocking, thread safety, or task tracking.
  • If you need thread-safe FIFO without extra bookkeeping, SimpleQueue is also worth considering.

Related reading
Course
Intermediate
27 lessons
15 hours
DSA Fundamentals

Master algorithmic patterns and data structures through hands-on LeetCode-style problems - from arrays and hashing to dynamic programming and advanced graphs.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

All Rights Reserved.