Await Is Not a Context Switch: Understanding Python's Coroutines vs. Tasks

https://news.ycombinator.com/rss Hits: 2
Summary

Every engineer has had that moment during a review where a comment sticks in their head longer than it should.In my case, it was a simple suggestion:“You should add more locks here: this code is async, so anything might interleave.”The code in question touched a shared cache, and on the surface the comment made sense. Multiple asyncio tasks were hitting the same structure, and the function modifying it was async. Shouldn't that mean I need more locks?That review pushed me down a rabbit hole. Not about the cache (it was tiny) but about the mental model many engineers (including experienced ones) bring to Python's async system. A model shaped by JavaScript or C#: all languages where await means "yield to the runtime now."But Python isn't those languages. And misunderstanding this fundamental difference leads to unnecessary locking, accidental complexity, and subtle bugs.This post is the explanation I wish more engineers had.The misconception: await gives up control (in every language… right?)If you're coming from JavaScript, the rule is simple:Every await always yields to the event loop.Every async function always returns a task (a Promise).The moment you write await, the runtime can schedule something else.In C#, the story is nearly identical:async functions return Task<T> or Task.await always represents a suspension point.The runtime decides when to resume you.In Java's virtual-thread world (Project Loom), the principle is very similar: when you submit work to run asynchronously, typically via an ExecutorService backed by virtual threads, you're creating tasks. And when you call Future.get(), the virtual thread suspends until the result is ready. The suspension is inexpensive, but it still constitutes a full scheduling boundary.So developers internalize one big rule:“Any async boundary is a suspension point.“And then they bring that rule to Python.But Python is different: it has two async conceptsPython splits things into:1. CoroutinesDefined with async def, but not...

First seen: 2025-11-26 11:28

Last seen: 2025-11-26 12:28