7 routes42 sections324 units

Unit 6.1 · about 5 h

35 / 324

Work types, threads, processes, async tasks and the GIL

Concurrency overlaps work; it does not automatically make that work parallel. A workload and build-specific experiment is a better design input than a blanket claim about Python threads.

  • explain
  • measure

You can now

  • Choose threads, processes or async tasks from CPU work, I/O waits, shared state and cancellation needs.
  • Measure CPU-bound thread scaling on default and free-threaded CPython 3.14 builds without assuming their GIL state.
  • Identify a blocking call that prevents other event-loop tasks from progressing.

Covers

  • CPU-bound, I/O-bound, stateful and cancellation-sensitive work
  • Threads, processes and asynchronous tasks
  • Python GIL implications and extension-code release boundaries

Study, in this order

3 steps

  1. Concurrency models and Python workload choices
    AlgoMaster Concurrency

    Concurrency Models; then Threading vs Multiprocessing, Key Differences and When to Use Threading/Multiprocessing; Asyncio Fundamentals, The Event Loop and Common async/await Mistakes

    Depth · Use the models as a first pass. Check build-specific GIL and process-start claims against the 3.14 references below.

  2. Free-threaded CPython is a separate build
    Python concurrency documentation

    Identifying free-threaded Python; The global interpreter lock in free-threaded Python; Thread safety; Performance characteristics

  3. Process startup is part of the experiment
    Python concurrency documentation

    Contexts and start methods: spawn, fork and forkserver, including the 3.14 default changes and safe importing of the main module

Focus on

  • Default CPython 3.14 has a GIL. Pure Python CPU loops do not gain multicore parallelism from its threads; I/O waits and native code that releases the GIL are different cases.
  • Free-threaded builds can execute Python threads in parallel. Record sys.version, sysconfig.get_config_var('Py_GIL_DISABLED') and sys._is_gil_enabled() after imports; an unsupported extension can re-enable the GIL.
  • Async tasks share an event-loop thread and yield cooperatively. A synchronous CPU loop or time.sleep inside a task stalls that loop.
  • Processes isolate state but pay startup and serialization costs. In 3.14 fork is no longer the default anywhere: Linux and other POSIX platforms default to forkserver, while macOS and Windows use spawn. Select and report the context explicitly.

Reproduce closed-book

From a blank file, sum integers with a Python for-loop for four equal jobs of 5,000,000 iterations. Assert each result equals n*(n-1)//2. Compare serial, four threads and four spawned processes on both CPython 3.14 builds. Use one warm-up and five measured trials per mode, include pool startup and save raw times, CPU, full version and GIL state. A reference run on Intel Core i9-12900K gave median seconds serial/threads/processes of 0.304/0.321/0.153 on 3.14.4 default and 0.315/0.088/0.156 on 3.14.6 free-threaded with GIL disabled. These are observations, not required speedups. Also schedule a heartbeat around a synchronous blocking call, then replace it with an awaited nonblocking operation and explain the missing versus advancing heartbeat.

Traps

  • Treating a free-threaded executable name as proof that the GIL stayed disabled after imports.
  • Replacing the loop with sum(range(n)) and calling it the same pure Python workload, or comparing different total work across worker counts.
  • Calling asyncio.to_thread a CPU-parallelism guarantee on the default build. It keeps blocking I/O off the loop but does not remove the GIL.

Practice

The section mini-project covers this: matched-work concurrency comparisons and an event-loop blocking fault in the bounded worker pipeline.

Self-test

  1. Which model fits many socket waits with little CPU work?

  2. Why might processes lose on tiny jobs?

  3. Does no GIL mean no need for locks?

  4. Do these two build measurements isolate the cost of removing the GIL?

Completion criterion

Stop when

You have correctness-checked raw timings from both builds and can justify a model for CPU work, blocking I/O and cancellation-sensitive work without claiming a universal speedup.

Mark passed, then open 6.2 Only mark this when you can do it without notes.

Leads to

Resources for this unit

  • AlgoMaster Concurrency
    AlgoMasterprimarycourse
    Study Concurrency 101; the Python units on threads, the GIL, multiprocessing, asyncio and concurrent.futures; synchronization primitives; concurrency challenges; locking strategies; and concurrency patterns. Then solve Bounded Buffer, Thread-Safe Blocking Queue, Thread-Safe Rate Limiter and Task Scheduler with Dependencies.
  • Python concurrency documentation
    Python Software Foundationrequiredreference
    Use asyncio task groups, cancellation, queues and timeouts; concurrent.futures; multiprocessing; threading; and signal documentation to verify lifecycle and failure behavior.

Also in this section

  • High Performance Python, 3rd edition
    Micha Gorelick and Ian Ozsvald, O'Reillyrequiredimplementation
    Read Chapter 2 Profiling to Find Bottlenecks, Chapter 9 Asynchronous I/O, Chapter 10 The multiprocessing Module and Chapter 12 Using Less RAM, and use the companion code (https://github.com/mynameisfiber/high_performance_python_3e) as experiment starting points. Change the workloads and measure the regimes where concurrency helps, loses or only moves the bottleneck.
  • Operating Systems: Three Easy Pieces - concurrency
    Remzi and Andrea Arpaci-Dusseausupporttheory
    Read Chapters 26-33, from threads through event-based concurrency, for locks, condition variables, semaphores, concurrency bugs and event loops. Do selected homework only for a weak mechanism.
  • Docker guides
    Dockersupportimplementation
    Use the Python container guide and build best practices to run as non-root, pin dependencies, handle signals and test CPU and memory limits.
  • OpenTelemetry Python instrumentation
    OpenTelemetrysupportoperations
    Manually instrument one request so its structured logs, one low-cardinality metric and one trace share a correlation identity. Use the telemetry to locate one seeded fault.
  • Algorithmica - Getting Accurate Results
    Sergey Slotinsupportreference
    Use Measuring the Right Thing and Reducing Noise for benchmark design: input distribution, latency versus throughput, warm-up, frequency scaling and pinning. The examples are C++; the checks transfer to Python.
  • Timeouts, retries, and backoff with jitter
    AWS Builders' Library, Marc Brookerrequiredoperations
    Read Timeouts, Retries and backoff, and Jitter for deadline scope, idempotency, one retry owner and bounded retry load. Interpret the five-layer example as three total attempts per layer, not three retries plus the initial attempt.
  • Site Reliability Engineering - overload and troubleshooting
    Googlerequiredoperations
    Read Chapter 21, The Pitfalls of Queries per Second, Client-Side Throttling, Utilization Signals, Handling Overload Errors and Conclusions. Read Chapter 12, Triage, Examine, Diagnose, Test and Treat, and Making Troubleshooting Easier for a service runbook. Skip datacenter load-balancing implementation details.
  • Liveness, Readiness, and Startup Probes
    Kubernetesrequiredreference
    Read Liveness probe, Readiness probe and Startup probe for the different health decisions and failure actions. Apply the contracts to a local service; do not install Kubernetes or configure a cluster.

Quick find

Search Michi

Type to search every route, section, unit, topic and resource.

Enter opens the first result Esc closes

Reference

Keyboard shortcuts

n
Continue to the first unit not passed
j / k
Next / previous unit
1 2 3
Toggle learned, practised, passed
/
Open search
?
Show this help
Esc
Close open panels