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
- 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. - 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.
- 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.
- Thread Creation:
- Two producer threads and two consumer threads are created.
- 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.
Leave a Reply