Start here. This is the direct spoken answer to practice first.
Overview
Uses documented thread-safe scheduling APIs and keeps event-loop objects confined.
Most asyncio objects are not safe to manipulate directly from another OS thread. To schedule a normal callback, I use loop.call_soon_threadsafe(). To submit a coroutine, I use asyncio.run_coroutine_threadsafe(), which returns a concurrent future the calling thread can observe. Tasks and futures stay owned by the loop where they were created rather than being awaited or cancelled directly elsewhere.