As mentioned before, asyncio runs on a single thread. All asyncio.Future objects and coroutines are managed by this single event loop within that single thread. There’s no inherent need for them to be internally thread-safe because there’s only one thread actively operating on them at any given moment.

NOTE

Yep, so if you just use asyncio itself without any other ‘multi-thread/process’ magic, things should just work.

If you do try to call methods on an asyncio.Future (like set_result() or cancel()) from a different thread than the one running the asyncio event loop, you could introduce race conditions, as asyncio.Future doesn’t have internal locks to protect its state from simultaneous modification by an external thread.

NOTE

So, that is to say, the internal states of asyncio.Future is not really thread safe. So if two threads accessing the same asyncio.Future simultaneously, bad thing can happen.

Yep, that sounds reasonable.

The correct way to interact with an asyncio.Future from another thread is to use loop.call_soon_threadsafe(). This method specifically queues a callable to be run on the event loop’s thread, ensuring that the interaction with the asyncio.Future happens in a thread-safe manner (by being executed on the main event loop thread).