[Post-RFC] Stackless Coroutines

Thank you so much. I’ll definitely be playing with this.

I understand my post here might be out of place, especially since what I’m going to say does not give any meaningful critique issues that have come up in the related RFCs. I’m sure you (and and everyone involved) are already aware, but I just wanted to make it extra clear so you know how much having access to async-await means. It’s been the single feature that, for years, has stopped me, my company, and a lot of people I know from pervasively using Rust every day.


I can’t begin to express how important this is for me. I don’t think async and await can come fast enough.

Of all the proposed ergonomics and language improvements proposed for Rust, async, await is the biggest and the only showstopper that prevents me (on a personal level) and also the entire company where I work from pervasively adopting Rust and using it in every new project we touch. It prevents us from all-inning on Rust, because writing callback-based code (whether through callback passing, or Future::and_then).

I don’t mean to say that the other Rust language improvements that are happening now aren’t important. They are, and I’m looking forward to them too. But the pain of not having them is nowhere near the pain of not having async-await.

For small, single-purpose programs, callbacks and Future::and_then is readable and can be relatively clean. I’ve used futures extensively when writing TCP proxies, BGP routers, and other programs whose purpose can be described in a one line. That’s OK.

But in large, complex services (100k-1m lines) where there’s a lot of logic driving a bunch of different services, and each service serving a thousand (or even only one hundred) connections, having async, await sugar is so powerful that we are reluctantly “forced” to fall back to using C++ (co_await), C# (await), and Go (native).


Right now, translating a 100 line await function to Tokio means a lot of spaghetti, nesting, and boilerplate (especially in returning futures allocation-free futures when types don’t match, like for an if pre-condition { return} else { happy route }). An otherwise simple function quickly becomes an await-supporting language turns into a mess of multiply indented hundred lines, especially so if you try to add loops and retries.

The alternative is to write code that spawns a thread per task, but even with only one hundred concurrent tasks, the cost of context switching quickly matches the cost of the work itself (!)

Finally, it is my opinion that once we have async-await, only then will we begin to see a sprawl of high-quality crates that can begin to be used in networked environments where thousands of operations are run every second. Right now, lots of libraries block, and that’s an instant disqualification for any environment where concurrency and latency are important (which is to say a lot).


I completely understand that the community and core teams want to get this right, but I’d definitely prefer to see an MVP in the compiler today (under a flag), rather than five months from now.

17 Likes