Hasty Briefsbeta

Bilingual

What Python's asyncio primitives get wrong about shared state

7 hours ago
  • #asyncio
  • #concurrency
  • #python
  • Python's asyncio primitives like Event, Condition, and Queue have limitations in handling shared state under real concurrency.
  • Polling for state changes introduces tradeoffs between latency and efficiency, leading to wasted CPU cycles and arbitrary sleep intervals.
  • asyncio.Event simplifies waiting for state changes but is limited to boolean states, requiring multiple events for complex state machines.
  • asyncio.Condition allows waiting on arbitrary predicates but can miss intermediate states due to the 'lost update' problem in fast transitions.
  • A solution using per-consumer queues ensures no state transitions are missed by buffering every change for each consumer.
  • The ValueWatcher class provides a production-ready implementation with thread safety, atomic registration, generic typing, and various wait methods.
  • ValueWatcher handles common patterns like waiting for specific states, non-None values, or any change, with support for timeouts and callbacks.
  • The implementation avoids the pitfalls of asyncio.Condition by ensuring consumers see every state transition, not just the current state.
  • ValueWatcher is used in Inngest's Python SDK for managing WebSocket connections, worker lifecycle, and graceful shutdown.