Concurrency line
Concurrency deep-dive
One cashier keeps a whole line moving by serving one basket, pausing for a phone call, then swapping to the next.
Stops explain each step. The film plays the whole ride.
- Serving a basket
- Stepping aside
- Coming back to the line
- Someone never gets a turn
Rafi gets the cashier
The only cashier starts Rafi’s basket. Nila is still waiting in line.
Next stop: Rafi steps aside
All stops
The everyday version
One checkout lane. The line is whoever could be served now. A phone call is stepping aside. Swapping baskets is the cost of changing customers. A second cashier would be a second core, which is the parallelism page.
- The lineis the Ready queue
Customers who could be served right now, waiting for the picker.
- The cashieris the Core
The only person who can have a basket open. One at a time.
- The phone callis the Blocked
A slow wait off to the side. The cashier does not stand and watch.
- A second cashieris another core
Two baskets open at the same moment. That is parallelism, not this page.
Interview questions
Say the short answer first. Go deeper only if they ask.
What is the difference between concurrency and parallelism?
Concurrency is many tasks in progress. Parallelism is more than one executing at the same instant.
One core can be concurrent by interleaving. Parallel needs several cores and a runtime that may use them. Python’s glossary says concurrency is tasks “at the same time”, then defines parallelism as several cores. Keep the interview split, and mention the glossary’s wording.
“They are two words for the same thing.”
Who schedules Python threads?
The operating system. The interpreter only asks for a switch.
sys.setswitchinterval sets an ideal timeslice. The docs say the real gap can be longer, especially across a long C call, and that the interpreter has no scheduler of its own. CPython 3.14’s GIL runtime defaults that ideal to 5000 µs in Python/ceval_gil.c. The sys page does not state the number.
“Python has its own thread scheduler.”
What does a context switch cost?
The core saves one task’s place and loads another’s.
It saves and restores the program counter, registers, and stack pointer. Caches and the TLB then hold the wrong working set. Do not quote a microsecond figure unless you measured that machine. A slice shorter than the save can make the program slower.
“Switching is free.”
What happens if an asyncio task never awaits?
It keeps the loop. Every other task waits.
Cooperative scheduling only switches at a point that suspends. A tight loop with no await never returns to the loop. await asyncio.sleep(0) suspends and lets ready tasks run. A thread is different: the OS can preempt it, and a GIL build still switches bytecode on the ideal slice.
“The event loop will interrupt it anyway.”
What is starvation?
A ready task never gets picked, so it makes no progress.
It is a liveness failure, not a wrong answer. The task is runnable the whole time. A scheduler that always prefers the task that just ran, or that ranks priorities badly, can starve the others. Fairness is a policy. The hardware does not promise it.
“If it is ready, it will run soon.”
Cheat-sheet
Commands you will actually type.
import sys
print(sys.getswitchinterval())Print the ideal gap between Python thread switches, in seconds.
sys.setswitchinterval(0.001)Ask for a shorter ideal slice. The real gap can still be longer.
async def spin():
while True:
pass # never awaits, so the loop freezesA task that never suspends keeps the event loop to itself.
await asyncio.sleep(0)Suspend so the loop can run whoever else is ready.
# CPython 3.14, Python/ceval_gil.c
#define DEFAULT_INTERVAL 5000 /* microseconds */The source default is 5000 µs. The sys docs do not print that number.