Concurrency and Modules
Queue Worker
A Queue hands work from one thread to another. The source stays in one pane,
and replay uses thread colors to show producer and consumer events.
queue handoff
`put()` adds work, and `get()` removes it. A small sentinel value can tell the consumer that no more work is coming.
Producer and Consumer
queue_worker.py
Replay: real traced execution (multi-file project)
import queue
import threading
work = queue.Queue()
def producer(count):
for number in range(1, count + 1):
item = "job-" + str(number)
work.put(item)
print("queued=" + item)
work.put("done")
def consumer():
while True:
item = work.get()
if item == "done":
print("stopped")
break
print("handled=" + item)
count = 2
producer_thread = threading.Thread(target=producer, args=(count,))
consumer_thread = threading.Thread(target=consumer)
producer_thread.start()
consumer_thread.start()
producer_thread.join()
consumer_thread.join()
import queue
import threading
work = queue.Queue()
def producer(count):
for number in range(1, count + 1):
item = "job-" + str(number)
work.put(item)
print("queued=" + item)
work.put("done")
def consumer():
while True:
item = work.get()
if item == "done":
print("stopped")
break
print("handled=" + item)
count = 3
producer_thread = threading.Thread(target=producer, args=(count,))
consumer_thread = threading.Thread(target=consumer)
producer_thread.start()
consumer_thread.start()
producer_thread.join()
consumer_thread.join()
work ← ⟨Queue A⟩, count ← 2, producer_thread ← <Thread(Thread-1 (producer), initial)>
5work→ ⟨Queue A⟩ = queue<module 'queue' from '/usr/local/lib/python3.12/queue.py'>.Queue()678def producer(count):9 for number in range(1, count + 1):10 item = "job-" + str(number)11 work.put(item)12 print("queued=" + item)13 work.put("done")141516def consumer():17 while True:18 item = work.get()19 if item == "done":20 print("stopped")21 break22 print("handled=" + item)232425count→ 2 = 2 #@count=32627producer_thread→ <Thread(Thread-1 (producer), initial)> = threading<module 'threading' from '/usr/local/lib/python3.12/threading.py'>.Thread(target=producer⟨function producer B⟩, args=(count2,))28consumer_thread→ <Thread(Thread-2 (consumer), initial)> = threading<module 'threading' from '/usr/local/lib/python3.12/threading.py'>.Thread(target=consumer⟨function consumer C⟩)2930producer_thread<Thread(Thread-1 (producer), initial)>.start()31consumer_thread.start()def producer(count):
8def producer(count2):9 for number in range(1, count + 1):10 item = "job-" + str(number)item ← job-1
pass 1 of 28def producer(count):9 for number1 in range(1, count2 + 1):10 item→ job-1 = "job-" + str(number1)11 work⟨Queue A⟩.put(itemjob-1)12 print("queued=" + itemjob-1)13 work.put("done")outputqueued=job-1item ← job-2
pass 2 of 28def producer(count):9 for number2 in range(1, count2 + 1):10 item→ job-2 = "job-" + str(number2)11 work⟨Queue A⟩.put(itemjob-2)12 print("queued=" + itemjob-2)13 work.put("done")outputqueued=job-2work.put("done")
12 print("queued=" + item)13work⟨Queue A⟩.put("done")producer_thread ← <Thread(Thread-1 (producer), stopped 139437626431168)>
30producer_thread→ <Thread(Thread-1 (producer), stopped 139437626431168)>.start()31consumer_thread<Thread(Thread-2 (consumer), initial)>.start()32producer_thread.join()item ← job-1
pass 1 of 316def consumer():17 while True:18 item→ job-1 = work⟨Queue A⟩.get()19 if item == "done":20 print("stopped")21 break22 print("handled=" + itemjob-1)outputhandled=job-1All 3 passes — pass 1 is the card above pass item1 job-1 2 job-2 3 done if item == "done":
18item = work.get()19if itemdone == "done":20 print("stopped")21 break22print("handled=" + item)outputstoppedconsumer_thread ← <Thread(Thread-2 (consumer), stopped 139437626431168)>
30producer_thread.start()31consumer_thread→ <Thread(Thread-2 (consumer), stopped 139437626431168)>.start()32producer_thread<Thread(Thread-1 (producer), stopped 139437626431168)>.join()33consumer_thread<Thread(Thread-2 (consumer), stopped 139437626431168)>.join()
work ← ⟨Queue A⟩, count ← 3, producer_thread ← <Thread(Thread-1 (producer), initial)>
5work→ ⟨Queue A⟩ = queue<module 'queue' from '/usr/local/lib/python3.12/queue.py'>.Queue()678def producer(count):9 for number in range(1, count + 1):10 item = "job-" + str(number)11 work.put(item)12 print("queued=" + item)13 work.put("done")141516def consumer():17 while True:18 item = work.get()19 if item == "done":20 print("stopped")21 break22 print("handled=" + item)232425count→ 3 = 32627producer_thread→ <Thread(Thread-1 (producer), initial)> = threading<module 'threading' from '/usr/local/lib/python3.12/threading.py'>.Thread(target=producer⟨function producer B⟩, args=(count3,))28consumer_thread→ <Thread(Thread-2 (consumer), initial)> = threading<module 'threading' from '/usr/local/lib/python3.12/threading.py'>.Thread(target=consumer⟨function consumer C⟩)2930producer_thread<Thread(Thread-1 (producer), initial)>.start()31consumer_thread.start()def producer(count):
8def producer(count3):9 for number in range(1, count + 1):10 item = "job-" + str(number)item ← job-1
pass 1 of 38def producer(count):9 for number1 in range(1, count3 + 1):10 item→ job-1 = "job-" + str(number1)11 work⟨Queue A⟩.put(itemjob-1)12 print("queued=" + itemjob-1)13 work.put("done")outputqueued=job-1All 3 passes — pass 1 is the card above pass numberitem1 1 job-1 2 2 job-2 3 3 job-3 work.put("done")
12 print("queued=" + item)13work⟨Queue A⟩.put("done")producer_thread ← <Thread(Thread-1 (producer), stopped 132846169237184)>
30producer_thread→ <Thread(Thread-1 (producer), stopped 132846169237184)>.start()31consumer_thread<Thread(Thread-2 (consumer), initial)>.start()32producer_thread.join()item ← job-1
pass 1 of 416def consumer():17 while True:18 item→ job-1 = work⟨Queue A⟩.get()19 if item == "done":20 print("stopped")21 break22 print("handled=" + itemjob-1)outputhandled=job-1All 4 passes — pass 1 is the card above pass item1 job-1 2 job-2 3 job-3 4 — consumer_thread ← <Thread(Thread-2 (consumer), started 132846169237184)>
17 while True:18 item→ done = work⟨Queue A⟩.get()19 if item == "done":20 print("stopped")21 break22 print("handled=" + item)232425count = 32627producer_thread = threading.Thread(target=producer, args=(count,))28consumer_thread = threading.Thread(target=consumer)2930producer_thread.start()31consumer_thread→ <Thread(Thread-2 (consumer), started 132846169237184)>.start()32producer_thread<Thread(Thread-1 (producer), stopped 132846169237184)>.join()33consumer_thread<Thread(Thread-2 (consumer), started 132846169237184)>.join()if item == "done":
18item = work.get()19if itemdone == "done":20 print("stopped")21 break22print("handled=" + item)outputstoppedconsumer_thread ← <Thread(Thread-2 (consumer), stopped 132846169237184)>
32producer_thread.join()33consumer_thread→ <Thread(Thread-2 (consumer), stopped 132846169237184)>.join()