Stop by Stop

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.

Words to know

Stops explain each step. The film plays the whole ride.

Explain it
Route
The lineNila in lineThe cashierServing RafiPhone callNobody aside
  • Serving a basket
  • Stepping aside
  • Coming back to the line
  • Someone never gets a turn
Stop 1 of 7

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?
Short answer

Concurrency is many tasks in progress. Parallelism is more than one executing at the same instant.

If they dig deeper

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.

Answer that loses points

“They are two words for the same thing.”

Who schedules Python threads?
Short answer

The operating system. The interpreter only asks for a switch.

If they dig deeper

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.

Answer that loses points

“Python has its own thread scheduler.”

What does a context switch cost?
Short answer

The core saves one task’s place and loads another’s.

If they dig deeper

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.

Answer that loses points

“Switching is free.”

What happens if an asyncio task never awaits?
Short answer

It keeps the loop. Every other task waits.

If they dig deeper

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.

Answer that loses points

“The event loop will interrupt it anyway.”

What is starvation?
Short answer

A ready task never gets picked, so it makes no progress.

If they dig deeper

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.

Answer that loses points

“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 freezes

A 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.

Sources