A lot of the time it’s not about options. It’s about not messing up the async pattern.
If you have something that either:
- requires a lot of CPU time
- requires to run permanently, independently to the caller’s future polling. Then you can spawn it on a global tokio executor.
If not, just use future polling tricks like the futures::join!() macro or a stream with .buffered(). It won’t be slower. The bottle neck is IO. Not the program.
Personally I even try to replace the heavy reqwest library with ureq + blocking, and it works perfectly and compiles faster (you can see that in the api_bindium crate)















Most of the time, async tutorial makes you learn tokio, not async. If your program can run with only tokio::main, then you learned async. If not, you learnt tokio (except if you are spawning a future that should never stop)
For example, my pet project only uses tokio::main to do async stuff. The only instances of tokio::spawn is make sure some SQLite transactions get polled to completion. I do need to replace them with a proper mechanism now that sqlx supports smol-rs