Concurrency in the Late-Night Kitchen
·
Course overview
1
The first night's queue: concurrency and parallelism
2
Hiring more cooks: threading basics
3
The chalkboard is wrong: race conditions and Lock
4
Only three burners: synchronization tools
5
Knives and boards: deadlock
6
The ticket rail: queue
7
Agency cooks: concurrent.futures
8
Why the dough won't go faster: the GIL and parallelism
9
One floor manager for every table: first steps in asyncio
10
The group booking falls through: structured concurrency
11
The floor freezes: blocking calls and mixing tools
12
The critic's night: putting it all together
Time 0:00–0:50
Tonight's ticket
#01 · Night one
Trouble
Eight parties walk in the moment the doors open. The sous-chef makes the orders alone, one at a time, and just stands there while each soup comes to a boil.
Goal
Get all eight orders out in under a second.
Late-night diner Dongsi
Ten o'clock on opening night. The doors open and the guests pour in. You put the first order's soup on the heat and stand in front of the pot until it boils. Three minutes later the first bowl goes out, and you start on the second order.
Chef Yoon Seoyeon glances at her timer. "While that soup was boiling, what were your hands doing? Nothing. That's tonight's problem."
Let's fake the wait for a pot to boil in Python. time.sleep(0.3) means "wait 0.3 seconds and do nothing." Think of it as three minutes squeezed into 0.3 seconds.
import time
def make_order(n):
time.sleep(0.3) # wait for the soup to boil
return f"#{n}"
start = time.perf_counter()
done = [make_order(n) for n in range(1, 9)]
print(f"{time.perf_counter() - start:.2f}s", done)
# 2.40s ['#1', '#2', '#3', '#4', '#5', '#6', '#7', '#8']time.perf_counter() is the clock you use for timing. Read it twice and subtract to get the seconds that passed in between.The last digit may change a little from run to run. Timing results are always approximate.
Kitchen work comes in two kinds.
| Waiting work (I/O) | Hands-on work (CPU) | |
|---|---|---|
| In the kitchen | boiling soup, baking in the oven, waiting for a delivery | kneading dough, julienning vegetables |
| In a program | network responses, reading files, databases | calculation, compression, image processing |
| Meanwhile | the person is idle | the person is busy the whole time |
Concurrency saves a lot of time when there is plenty of waiting work: while one soup boils, you put another pot on. Hands-on work only gets faster with more actual people, and Python has a hidden rule about that. We'll get to it in Lesson 8.
The two words often get mixed up, but they mean different things.
Parallelism is one way to get concurrency. In a kitchen full of waiting work, concurrency alone makes things much faster, even with only one pair of hands. On the timeline below, switch between "Alone, one by one" and "Several cooks." Each bar is one order, and the horizontal axis is time.
Kitchen timeline
Orders
6
Cooks
3
Cooking
Waiting
Cancelled
Failed
time.sleep, and each bar is drawn from the moment that order actually started and finished.If every order takes the same time, the total is "the most orders any one cook handles × the time per order."
import math
def estimate(orders, cooks, each=0.3):
rounds = math.ceil(orders / cooks) # the most orders a single cook handles
return round(rounds * each, 2)
for cooks in (1, 3, 4, 8, 16):
print(cooks, estimate(8, cooks))
# 1 2.4
# 3 0.9
# 4 0.6
# 8 0.3
# 16 0.3Python has three tools for doing several things at once. Tonight is just a taste; from the next lesson on we dig into them one at a time.
import threading
threads = [threading.Thread(target=make_order, args=(n,)) for n in range(1, 9)]
for th in threads:
th.start() # eight cooks start at once
for th in threads:
th.join() # wait until everyone is done
# about 0.30 simport asyncio
async def make_order_async(n):
await asyncio.sleep(0.3) # look after other orders while waiting
return f"#{n}"
async def main():
return await asyncio.gather(*(make_order_async(n) for n in range(1, 9)))
print(asyncio.run(main()))
# ['#1', '#2', '#3', '#4', '#5', '#6', '#7', '#8'] (about 0.31 s)| Tool | In kitchen terms | Good for | Lessons |
|---|---|---|---|
threading | several cooks in the same kitchen | waiting work, old code | 2–7 |
multiprocessing | a branch kitchen with its own fridge | hands-on work (CPU) | 8 |
asyncio | one floor manager covering dozens of tables | lots and lots of waiting work | 9–11 |
Chef's tip
Sure, more cooks means faster. It also means a noisier kitchen. What happens when two people write a number on the same chalkboard at the same time? You'll see it for yourself in Lesson 3.
More cooks come at a cost.
Tonight's goal was to get eight orders out in under a second. Every order is waiting work, so eight cooks taking one each will do it.
start = time.perf_counter()
threads = [threading.Thread(target=make_order, args=(n,)) for n in range(1, 9)]
for th in threads:
th.start()
for th in threads:
th.join()
print(f"{time.perf_counter() - start:.2f}s")
# 0.30sThe chef stops her timer. "From 2.4 seconds to 0.3. Not bad for a first night. But once there are eight cooks, who keeps count of how many each one made?"
Service log — Night one. All 8 orders were waiting work, so 8 cooks split them and finished in 0.3 seconds. Tomorrow we hire cooks for real.
time.sleep(0.3) in make_order with a loop that adds up numbers (hands-on work), run it on threads, and time whether it gets faster. If the result looks odd, Lesson 8 explains why.Chef's recipe card
Waiting work (I/O) gets much faster with concurrency. Hands-on work (CPU) needs real parallelism.
Concurrency = taking turns; parallelism = running at the same instant.
Timing: start = time.perf_counter() … time.perf_counter() - start
Three tools: threading (many cooks), multiprocessing (many kitchens), asyncio (one manager on the floor).
Concurrency isn't free: overhead and new kinds of bugs come with it.
Get news about new lessons
We'll email you when this course gets new lessons or a follow-up course opens.
R
ReflexKR
Learn Python and Reflex by doing. Every example was run and verified on Reflex 0.10.0.
ReflexKR is free, with no banner ads. If it helped you, you can support it with a coffee. ☕ Buy us a coffee
Affiliate disclosure© 2026 ReflexKR · Since 2026 · CC BY-NC 4.0
Questions & answers
Ask anything about this lesson. Questions from every language version of this page appear together.