I’ve never understood the “async I/O is too complicated, why can’t we just use goroutines?” criticism of Rust. You can! They’re called threads, and they work great.
We tried goroutines in Rust, and they weren’t really any more performant than OS threads. Certainly not enough to justify the complexity increase in FFI, etc.
Add some zeroes then. At some point you run into the virtual memory / stack size issue. Unless you're suggesting running rust with a 4KiB thread stack. Granted it probably doesn't matter that much for most people.
Stack size and the approach to detecting overflow are orthogonal to 1:1 vs. M:N threading. Regardless, the address space size for Linux userspace usage on x86_64 or arm64 with 4-level page tables is 128TiB. There's room for millions of threads even with an 8M stack mapping.
It doesn't rely on overcommit either. Fresh PROT_NONE mappings don't count towards the memory accounting limit even with overcommit disabled. Dynamically unprotecting the stacks as the memory is touched works fine and is the approach Linux uses for the main thread stack anyway.
Starting out with 4KiB thread stacks for Rust and expanding them into the reserved PROT_NONE mapping as the pages are touched works fine. However, there's no real point when overcommit is enabled, other than to work around broken heuristic overcommit, but that shouldn't be used.