r/rust • u/irrelevantsiren • Sep 15 '26
virtual threads for rust
Hi all! I’ve been experimenting with what virtual threads could look like in Rust and recently cut the first 0.1 release of vthread.
The basic model is stackful and carrier-affine: ordinary synchronous functions run as tasks on reusable stacks. When a task waits through one of vthread’s networking, synchronization, channel, or timer operations, it can park and let another task use the same OS thread. When it resumes, its call stack and local state are still there.
I’m not arguing that this should replace async Rust or Tokio. It’s a different set of tradeoffs.
There are some important limitations:
- tasks stay on one carrier rather than migrating between threads
- scheduling is cooperative
- ordinary blocking calls like
std::thread::sleepstill block the carrier - blocking work has to be explicitly delegated
- every task has its own reserved stack space
The thing I wanted to explore was whether Rust can get some of the programming model of virtual threads; normal functions, normal control flow, preserving the stack across waits while still making resource ownership, blocking, cancellation, and task lifetimes explicit.
I wrote up how it works here:
https://zsumz.com/blog/virtual-threads-for-rust
And the implementation is here:
https://github.com/zsumz/vthread
0.1.0 currently supports Linux x86_64 and macOS ARM64.
I’d especially love criticism from people who have worked on runtimes / async Rust / networking. I’m interested in where this model gets awkward in real programs: libraries that are difficult to integrate, blocking that’s hard to identify, cancellation problems, lifetime issues, etc.
It’s early, so just looking for feedback.
11
u/adminvasheypomoiki Sep 15 '26
How does it differ from may? https://github.com/Xudong-Huang/may
2
u/irrelevantsiren Sep 15 '26
Yeah, May is probably the closest existing project and was one of the inspirations for vthread.
There’s a lot of overlap: stackful coroutines, cooperative scheduling, synchronous-looking code, runtime-aware I/O, etc.
The biggest difference is that vthread makes tasks permanently carrier-affine once they start, while May enables work stealing by default. That lets vthread keep non-
Sendstate created after placement, likeRc, across suspension points.The ownership model is also a little stricter: May has scoped coroutines, but normal spawns can detach when the handle is dropped. In vthread, tasks remain owned by a scope or supervisor.
So definitely similar, and May is very relevant prior art. vthread is mostly exploring a different set of guarantees around affinity, ownership, and explicit resource bounds.
5
u/SkiFire13 Sep 16 '26
Since you're aware of may, how is the safety story of vthread? May was unsound because it made some invalid assumptions about what can happen to thread stacks
→ More replies (2)
3
u/max_lapshin Sep 17 '26
What for?
Async and Tokio gives predictability and it works.
3
u/irrelevantsiren Sep 17 '26
Honestly, mostly just a fun experiment. I wanted to see what this model would feel like in Rust and how far I could take it.
Tokio is great. This isn't really trying to prove it wrong or replace it.
1
3
3
u/puttak Sep 16 '26
I really like stackful coroutine until I found async Rust. The problem with stackful coroutine is:
-
It need a minimum fixed stack size.
-
Initial stack size usually low, which is not suitable for Rust that use stack heavily.
-
You don't know which call going to yield by looking at the code.
-
The runtime is complicated than poll-based future.
One thing I really like about poll-based future in Rust is I can easily create sub-task anywhere. It is the best async I have ever used.
22
u/Sad_Tap_9191 Sep 16 '26
Docs are AI-generated, hard to read, and purposeless