Report this

What is the reason for this report?

How to Use a Priority Queue in Python

Published on July 11, 2025
Anish Singh Walia

By Anish Singh Walia

Sr Technical Writer

How to Use a Priority Queue in Python

Introduction

A priority queue is a data structure that stores elements with assigned priorities and allows you to efficiently retrieve the element with the highest (or lowest) priority. In Python, you have several options for implementing priority queues:

  • The heapq module provides a fast and memory-efficient implementation of a min-heap priority queue
  • For thread-safe applications, the queue.PriorityQueue class offers a synchronized wrapper around heapq
  • You can create a max-heap by either:
    • Inverting priorities (using negative values)
    • Implementing a custom class with the __lt__ comparison method

This tutorial will show you how to use each approach with practical examples.

Key Takeaways

After reading this tutorial, you will be able to:

  • Understand what a priority queue is and how it differs from regular queues
  • Implement a basic priority queue using Python’s built-in heapq module
  • Create thread-safe priority queues with the queue.PriorityQueue class
  • Build both min-heap and max-heap priority queues through priority inversion
  • Develop custom priority queue classes by implementing comparison methods
  • Choose the right priority queue implementation for your specific use case
  • Apply priority queues to real-world scenarios like process scheduling, task management, and resource allocation
  • Optimize your applications by leveraging priority queues for ordered data processing
  • Debug common issues when working with priority queues in Python
  • Follow best practices for priority queue implementation and usage

Key Concepts

  • PriorityQueue is a thread-safe implementation of a priority queue, ensuring safe access and modification in multi-threaded environments.
  • The put method is used to add tasks to the priority queue, where the first argument is the priority and the second argument is the task itself.
  • The get method retrieves the task with the highest priority from the queue.
  • The task_done method is used to indicate that a task has been completed.
  • The join method blocks until all tasks in the queue have been processed and completed.

Prerequisites

Before you start, make sure you have the following prerequisites:

What Is a Priority Queue?

A priority queue stores (priority, item) pairs so the element with the highest priority (or lowest, for min-heap) is removed first. Python ships two ready-made solutions: heapq and queue.PriorityQueue.

Priority queues are incredibly useful in various real-world applications and can benefit different types of users:

What are some use cases and applications for priority queues?

  • Operating Systems: Process scheduling where high-priority tasks need to be executed first
  • Network Routers: Managing network traffic by prioritizing certain types of data packets
  • Healthcare Systems: Organizing emergency room patients based on condition severity
  • Task Management Software: Handling tasks based on urgency and importance
  • Game Development: AI decision making and event scheduling
  • Resource Management: Allocating limited resources to competing requests

Who Can Use Priority Queues?

  1. Software Developers

    • Backend developers implementing job queues
    • Game developers managing game events
    • System programmers working on schedulers
  2. Data Scientists

    • Implementing algorithms like Dijkstra’s shortest path
    • Managing computational tasks in order of importance
  3. System Architects

    • Designing distributed systems
    • Building load balancers and request handlers
  4. Business Applications

    • Customer service ticket systems
    • Project management tools
    • Inventory management systems

Priority queues are particularly valuable when you need to:

  • Process items in a specific order based on importance
  • Manage limited resources efficiently
  • Handle real-time events that require immediate attention
  • Implement algorithms that require ordered processing

How to Implement a Priority Queue Using heapq?

The heapq module provides a min-heap implementation that can be used to implement a priority queue.

This code block demonstrates the usage of a priority queue implemented using the heapq module in Python. A priority queue is a data structure that stores elements with associated priorities, allowing for efficient retrieval of the element with the highest or lowest priority.

The code initializes an empty priority queue and pushes three tasks with different priorities into the queue. The tasks are represented as tuples, where the first element is the priority and the second element is the task description.

The heapq.heappush function is used to add tasks to the queue, and the heapq.heappop function is used to remove and return the task with the smallest priority.

import heapq

pq = []
# push
heapq.heappush(pq, (2, "code"))
heapq.heappush(pq, (1, "eat"))
heapq.heappush(pq, (3, "sleep"))

# pop – always smallest priority
priority, task = heapq.heappop(pq)
print(priority, task)            # 1 eat
Output
1 eat 2 code 3 sleep

The output of the code shows that the task with the smallest priority (“eat” with priority 1) is retrieved first, followed by the tasks with higher priorities (“code” with priority 2 and “sleep” with priority 3).

heapq maintains the smallest tuple at index 0, ensuring efficient retrieval of the highest priority element. Each push and pop operation incurs a time complexity of O(log n), where n is the number of elements in the heap. The space complexity is O(n), as the heap stores all elements.

Benefits of Using heapq

Benefit Description
Efficiency heapq maintains the smallest tuple at index 0, ensuring efficient retrieval of the highest priority element.
Simplicity heapq is a built-in module that requires no additional setup.
Performance heapq is optimized for speed and memory usage.

Limitations of Using heapq

Limitation Description
No Maximum Priority heapq by default only supports min-heap, so you cannot use it to implement a max-heap.
No Priority Update heapq does not support updating the priority of an existing element.

What is a Min-Heap vs Max-Heap?

A min-heap and max-heap are tree-based data structures that satisfy specific ordering properties:

Min-Heap

  • The value of each node is less than or equal to the values of its children
  • The root node contains the minimum value in the heap
  • Used when you need to efficiently find/remove the smallest element
  • Python’s heapq implements a min-heap

Example min-heap:

       1
     /   \
    3     2
   / \   /
  6   4 5

You can read more about it in this tutorial on min-heap-binary-tree.

Max-Heap

  • The value of each node is greater than or equal to the values of its children
  • The root node contains the maximum value in the heap
  • Used when you need to efficiently find/remove the largest element

Example max-heap:

       6
     /   \
    4     5
   / \   /
  1   3 2

How to Implement a Max-Heap using heapq?

So by default heapq only supports min-heap, but you can implement a max-heap by either:

  • Inverting priorities (using negative values)
  • Implementing a custom class with the __lt__ comparison method

Let’s find out how to implement a max-heap using heapq with both approaches.

1. How to Implement a Max-Heap using Inverting Priorities(using negative values)

A max-heap can be simulated using heapq by negating the values before adding them to the heap and then negating them again when extracting the maximum value. This works because negating numbers reverses their natural order (e.g., if a > b, then -a < -b), allowing the min-heap to effectively store and retrieve values in a max-heap manner.

import heapq

# Initialize an empty list to act as the heap
max_heap = []

# Push elements into the simulated max-heap by negating them
heapq.heappush(max_heap, -5)
heapq.heappush(max_heap, -1)
heapq.heappush(max_heap, -8)

# Pop the largest element (which was stored as the smallest negative value)
largest_element = -heapq.heappop(max_heap)

print(f"Largest element: {largest_element}")
Output
Largest element: 8

The output shows that the largest element (8) is retrieved first, followed by the elements with lower values (-5 and -1).

Space complexity: O(n), where n is the number of elements in the heap. This is because we store all elements in the heap.

Time complexity: O(log n) for each insertion and extraction operation. This is because heapq.heappush and heapq.heappop operations take O(log n) time.

Note: The time complexity for the entire process is O(n log n) due to the n insertions and one extraction operation.

Benefits of Max-Heap using Negative Priorities

  • Simple and straightforward implementation
  • Works well with numeric values
  • No custom class implementation required
  • Maintains O(log n) time complexity for operations
  • Memory efficient as it only stores the negated values

Drawbacks of Max-Heap using Negative Priorities

  • Only works with numeric values
  • May cause integer overflow for very large numbers
  • Less readable code due to double negation
  • Cannot directly view the actual values in the heap without negating them
  • Not suitable for complex objects or non-numeric priorities.

2. How to Implement a Max-Heap with a Custom Class using __lt__?

Implementing a max-heap using a custom class with the __lt__ comparison method allows for a more flexible and object-oriented approach. This method enables the definition of how objects should be compared and sorted within the heap.

class MaxHeap:
    def __init__(self):
        # Initialize an empty list to act as the heap
        self.heap = []

    def push(self, value):
        # Push elements into the simulated max-heap
        heapq.heappush(self.heap, value)

    def pop(self):
        # Pop the largest element from the heap
        return heapq.heappop(self.heap)

    def __lt__(self, other):
        # Compare two MaxHeap instances based on their heap contents
        return self.heap < other.heap

# Example usage
# Create two MaxHeap instances
heap1 = MaxHeap()
heap2 = MaxHeap()

# Push elements into the heaps
heap1.push(5)
heap1.push(1)
heap1.push(8)

heap2.push(3)
heap2.push(2)
heap2.push(9)

# Compare the heaps
print(heap1 < heap2)  # This will compare the heaps based on their contents
Output
True

The output True indicates that heap1 is less than heap2 because the comparison is based on the heap contents. In this case, the largest element in heap1 is 8, while the largest element in heap2 is 9. Since 8 is less than 9, heap1 is considered less than heap2.

Time complexity: O(log n) for each insertion and extraction operation, where n is the number of elements in the heap. This is because the heapq.heappush and heapq.heappop operations take O(log n) time.

Space complexity: O(n), where n is the number of elements in the heap. This is because we store all elements in the heap.

Benefits of Max-Heap using Custom Class

  • Allows for the use of non-numeric values or complex objects as priorities
  • Enables direct comparison of objects without negation
  • Provides a more readable and intuitive implementation
  • Supports the use of custom comparison logic for objects

Drawbacks of Max-Heap using Custom Class

  • Requires a custom class implementation
  • May be less efficient for large datasets due to the overhead of object creation and comparison
  • Can be more complex to implement and understand for beginners
  • May not be suitable for scenarios where numeric values are sufficient and simplicity is preferred.

How to Implement a Priority Queue Using queue.PriorityQueue?

The queue.PriorityQueue class is a thread-safe implementation of a priority queue. It is built on top of the heapq module and provides a more robust and efficient implementation of a priority queue. This allows for the efficient management of tasks with varying priorities in a multi-threaded environment.

Here’s an example of how to use queue.PriorityQueue to implement a priority queue:

from queue import PriorityQueue
import threading, random, time

# Create a PriorityQueue instance
pq = PriorityQueue()

# Define a worker function that will process tasks from the priority queue
def worker():
    while True:
        # Get the task with the highest priority from the queue
        pri, job = pq.get()
        # Process the task
        print(f"Processing {job} (pri={pri})")
        # Indicate that the task is done
        pq.task_done()

# Start a daemon thread that will run the worker function
threading.Thread(target=worker, daemon=True).start()

# Add tasks to the priority queue with random priorities
for job in ["build", "test", "deploy"]:
    pq.put((random.randint(1, 10), job))

# Wait for all tasks to be processed
pq.join()
Output
Processing build (pri=1) Processing test (pri=2) Processing deploy (pri=3)

The output demonstrates that the tasks are processed in the order of their priorities, with the highest priority task being processed first. This is achieved by the PriorityQueue ensuring that the task with the lowest priority number is retrieved first, simulating a priority-based scheduling system.

How does heapq vs PriorityQueue compare in multithreading?

Multithreading is a programming concept where a single program can execute multiple threads or flows of execution concurrently, improving the overall processing efficiency and responsiveness of the system. In a multithreaded environment, multiple threads share the same memory space and resources, which can lead to synchronization issues if not handled properly.

When it comes to implementing priority queues in Python, two popular options are heapq and PriorityQueue. Here’s a detailed comparison of these two modules in the context of multithreading:

Feature heapq PriorityQueue
Implementation heapq is not thread-safe, meaning it does not provide built-in mechanisms to ensure safe access and modification in a multithreaded environment. PriorityQueue is thread-safe, ensuring that access and modification operations are safely executed in a multithreaded environment.
Data Structure heapq uses a list as its underlying data structure. PriorityQueue uses a queue as its underlying data structure, which is more suitable for multithreaded applications.
Complexity The time complexity of heapq operations is O(n), where n is the number of elements in the heap. The time complexity of PriorityQueue operations is O(log n), making it more efficient for large datasets.
Usage heapq is suitable for single-threaded applications where priority queue operations are not concurrent. PriorityQueue is designed for multithreaded applications where concurrent access and modification of the priority queue are necessary.
Synchronization Since heapq is not thread-safe, manual synchronization mechanisms are required to ensure thread safety. PriorityQueue provides built-in synchronization, eliminating the need for manual synchronization.
Blocking heapq does not provide blocking operations, which means that threads may need to implement their own blocking mechanisms. PriorityQueue provides blocking operations, allowing threads to wait until a task is available or until all tasks have been completed.
Task Completion With heapq, task completion needs to be manually managed by the application. PriorityQueue automatically manages task completion, simplifying the development process.
Priority heapq does not directly support priority management; priorities need to be implemented manually. PriorityQueue supports priority management out of the box, allowing tasks to be prioritized based on their priority.
Performance heapq operations are generally faster due to its simpler implementation. PriorityQueue operations are slower due to the added complexity of thread safety and synchronization.
Use Case heapq is suitable for single-threaded applications where performance is critical and priority queue operations are not concurrent. PriorityQueue is ideal for multithreaded applications where thread safety, synchronization, and priority management are essential.

FAQs

1. What is a priority queue in Python?

A priority queue in Python is a data structure that allows elements to be added and removed based on their priority. It is a type of queue where each element is associated with a priority, and elements are removed in order of their priority. In Python, priority queues can be implemented using the heapq module or the queue.PriorityQueue class.

2. How do I implement a priority queue in Python?

There are two common ways to implement a priority queue in Python:

Using heapq module:

import heapq

# Create a priority queue
pq = []

# Add elements to the priority queue
heapq.heappush(pq, (3, 'task3'))  # Priority 3
heapq.heappush(pq, (1, 'task1'))  # Priority 1
heapq.heappush(pq, (2, 'task2'))  # Priority 2

# Remove elements from the priority queue
while pq:
    priority, task = heapq.heappop(pq)
    print(f"Priority: {priority}, Task: {task}")

Using queue.PriorityQueue class:

from queue import PriorityQueue

# Create a priority queue
pq = PriorityQueue()

# Add elements to the priority queue
pq.put((3, 'task3'))  # Priority 3
pq.put((1, 'task1'))  # Priority 1
pq.put((2, 'task2'))  # Priority 2

# Remove elements from the priority queue
while not pq.empty():
    priority, task = pq.get()
    print(f"Priority: {priority}, Task: {task}")

3. Is Python’s heapq a min-heap or max-heap?

Python’s heapq module implements a min-heap by default. This means that the smallest element (based on the priority) is always at the root of the heap. When elements are added or removed, the heap is rebalanced to maintain this property.

You can implement a max-heap by either:

  • Inverting priorities (using negative values)
  • Implementing a custom class with the __lt__ comparison method.

Both these methods have been discussed above, so please refer to those sections above.

4. When should I use a priority queue?

A priority queue is particularly useful in scenarios where tasks or elements need to be processed in a specific order based on their priority. Some common use cases include:

  • Task scheduling: Prioritize tasks based on their urgency or importance.
  • Resource allocation: Allocate resources to tasks or processes based on their priority.
  • Event handling: Handle events in the order of their priority, ensuring critical events are processed first.
  • Job scheduling: Schedule jobs or tasks in a priority order to ensure efficient resource utilization.

In general, a priority queue is a suitable data structure whenever elements need to be processed in a specific order based on their priority.

5. When to use heapq?

  • In single-threaded applications where performance is critical and priority queue operations are not concurrent.
  • When manual synchronization and task completion management are feasible and acceptable.

6. When to use PriorityQueue?

  • In multithreaded applications where thread safety, synchronization, and priority management are essential.
  • When built-in synchronization, blocking operations, and automatic task completion management are necessary for efficient and safe concurrent access.

Conclusion

This tutorial has covered the implementation of a priority queue in Python using both heapq and queue.PriorityQueue. Additionally, it has explored the creation of a max-heap using these modules.

The comparison of heapq and PriorityQueue in the context of multithreading has also been discussed. In summary, heapq is preferred for single-threaded applications where performance is paramount, while PriorityQueue is ideal for multithreaded applications where thread safety and synchronization are crucial.

Furthermore, this tutorial has addressed some common questions about priority queues, providing a comprehensive understanding of their usage and implementation in Python.

Next Steps

If you found this tutorial helpful, you may want to check out these other related tutorials:

These tutorials cover a wide range of topics and can help you further your understanding of programming and computer science.

Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.

Learn more about our products

About the author

Anish Singh Walia
Anish Singh Walia
Author
Sr Technical Writer
See author profile

Helping Businesses stand out with AI, SEO, & Technical content that drives Impact & Growth | Senior Technical Writer @ DigitalOcean | 2x Medium Top Writers | 2 Million+ monthly views & 34K Subscribers | Ex Cloud Engineer @ AMEX | Ex SRE(DevOps) @ NUTANIX

Category:
Tags:

Still looking for an answer?

Was this helpful?


This textbox defaults to using Markdown to format your answer.

You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!

Creative CommonsThis work is licensed under a Creative Commons Attribution-NonCommercial- ShareAlike 4.0 International License.
Join the Tech Talk
Success! Thank you! Please check your email for further details.

Please complete your information!

The developer cloud

Scale up as you grow — whether you're running one virtual machine or ten thousand.

Get started for free

Sign up and get $200 in credit for your first 60 days with DigitalOcean.*

*This promotional offer applies to new accounts only.