Learn the concept
Threads can help integrate blocking I/O with concurrent work. Processes can isolate CPU-heavy computation and use multiple cores, with serialization and startup overhead. The best choice depends on the workload and runtime; measure instead of assuming more workers always help.
A queue decouples producers from consumers. Bound its size so a fast producer cannot consume all memory while workers are slow. Backpressure means slowing, rejecting, or deferring incoming work when capacity is exhausted.
Define how jobs are acknowledged and recovered after a worker fails. An in-memory queue does not preserve work across process restarts. Start with a local bounded queue to learn the behavior, then use durable storage when tasks must survive failures. Keep worker functions small and return structured outcomes.
Run and inspect
from queue import Queue, Full
queue = Queue(maxsize=2)
queue.put_nowait("a")
queue.put_nowait("b")
try:
queue.put_nowait("c")
except Full:
rejected = True
else:
rejected = False
assert rejected
assert queue.get_nowait() == "a"
queue.task_done()
Your exercise
Simulate a producer faster than a consumer. Compare an unbounded queue with a bounded queue and choose an explicit overload response.
Check your understanding
The producer cannot accumulate unlimited work and rejected or deferred jobs are visible to the caller.