You can spawn threads in Python. Async/await is (among other things) a control-flow primitive for single-threaded programs. C# also includes more or less the same async/await as these languages, as far as I know.
Not only do threads not really do the thing (in part because of the high cost of threads compared to alternatives), the alternative isn't only threads. Users of Lua, Greenlet, ucontext_t, libco, etc. have been able to write single-threaded code that's generic over the async-ness of its callees for decades. Recently there's a trend toward preferring needing to change 99 call sites and function signatures when adding a single piece of I/O to a single function though, needing to write two versions of each library, etc.
I'm not talking about trade-offs of async vs sync. I'm talking about the color article saying languages have "color" when one type of functions (sync) can't use results of another type of functions (async). If you have threads and mutexes, then one type can use the other, regardless of whether that's a good idea or not. The point is that there either is a hard unsolvable api-infecting limitation (like in JS) or there isn't.
Not only do threads not really do the thing (in part because of the high cost of threads compared to alternatives), the alternative isn't only threads. Users of Lua, Greenlet, ucontext_t, libco, etc. have been able to write single-threaded code that's generic over the async-ness of its callees for decades. Recently there's a trend toward preferring needing to change 99 call sites and function signatures when adding a single piece of I/O to a single function though, needing to write two versions of each library, etc.