No. The whole point of async is to avoid the overheads of actually using threads.
Imagine code that looks like, in pseudo code:
do forever
wait for some data from some source to process
process the data
make a response with the result
end
Further imagine that "wait for some data" takes a significant amount of time, perhaps a very long time. It blocks execution until data arrives. And that there are many instances of this loop running that accept data from different sources.
Doing this without threads is not going to work well. Once a wait
is hit all processing stops until the data from that source arrives. Even if there is data available from other sources in the mean time. You processor will spend much of it time idle, just waiting.
Traditional threads solve this problem by swapping the processors execution time amount the many instances of loops like that. That way if any source has any data available the thread that is waiting on it can proceed to do work daily quickly.
But threads have problems. A execution "context" has to me maintained for each thread, it's stack, it's processor register state etc. All this eats memory and takes time to constantly swap around as different threads get their share of CPU time.
Enter "async". Async code can have loops in it like the above, those loops can wait on data as long as they like.The compiler generates the required code to do the swapping around of processor execution. It's all done without threads and their overheads. Kind of how you might write a bunch of state machines to implement those loops if you had to get the job done on a system with no threads. The messy code to do all that is generated by the compiler instead.
Note that in the Rust async world they talk of "tasks" not "threads" to make the distinction.
In general async
is good for when you have lot of waiting to do. Threads are good for when you have a lot of computing to do, and preferably have multiple cores to run them on.
As for "ergonomics" I don't know. Rather than use the low level async facilities provided by Rust I ave only ever created async code using the Tokyo crate. So far I have never needed to even think about futures
and polling
. My code just looks like normal threaded code, but with async
and await
sprinkled around.
That all seems pretty neat to me. I don't have much desire to delve further under the hood.