Python Multithreading : Producer Consumer problem

·

The producer-consumer problem is a classic example of a multi-threading scenario where two types of processes (producers and consumers) share a common, finite-size buffer (queue). Producers produce data and place it into the queue, while consumers take data from the queue. The challenge is to ensure that producers do not add data to a full queue and consumers do not remove data from an empty queue.

Here’s a simple implementation of the producer-consumer problem using Python’s threading module and queue.Queue for thread-safe communication between the producer and consumer threads.

Producer-Consumer Example in Python

import threading
import queue
import time
import random

# Shared buffer (queue)
buffer = queue.Queue(maxsize=5)  # Limit the size of the buffer

# Producer function
def producer(producer_id):
    while True:
        item = random.randint(1, 100)  # Produce a random item
        buffer.put(item)  # Add item to the buffer
        print(f"Producer {producer_id} produced: {item}")
        time.sleep(random.uniform(0.5, 1.5))  # Sleep for a random time

# Consumer function
def consumer(consumer_id):
    while True:
        item = buffer.get()  # Remove item from the buffer
        print(f"Consumer {consumer_id} consumed: {item}")
        buffer.task_done()  # Signal that the item has been processed
        time.sleep(random.uniform(0.5, 1.5))  # Sleep for a random time

if __name__ == "__main__":
    # Create producer and consumer threads
    producers = [threading.Thread(target=producer, args=(i,)) for i in range(2)]  # 2 producers
    consumers = [threading.Thread(target=consumer, args=(i,)) for i in range(2)]  # 2 consumers

    # Start producer and consumer threads
    for p in producers:
        p.start()
    for c in consumers:
        c.start()

    # Join threads (they will run indefinitely in this example)
    for p in producers:
        p.join()
    for c in consumers:
        c.join()

Explanation

  1. Queue Initialization: A queue.Queue object is created with a maximum size of 5. This limits the number of items that can be in the buffer at any time.
  2. Producer Function:
  • Generates a random integer item.
  • Adds the item to the queue using buffer.put(item). If the queue is full, it will block until space becomes available.
  • Sleeps for a random period to simulate time taken to produce an item.
  1. Consumer Function:
  • Retrieves an item from the queue using buffer.get(). If the queue is empty, it will block until an item becomes available.
  • Processes the item and calls buffer.task_done() to signal that the item has been processed.
  • Sleeps for a random period to simulate time taken to consume an item.
  1. Thread Creation:
  • Two producer threads and two consumer threads are created.
  1. Thread Execution: All threads are started, and they run indefinitely in this example.

Note

  • This implementation will run indefinitely because the while True loops in both producer and consumer functions do not have a termination condition. In a real application, you might want to implement a mechanism to stop the threads gracefully (e.g., using an event flag).
  • You can also adjust the number of producers and consumers or the maximum size of the queue to see how it affects the system’s behavior.

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *