Go vs Rust Concurrency: Stackful vs Stackless Coroutines and Memory Impact

The article compares Go’s stackful, green‑thread model with Rust’s stackless, future‑based approach, explaining how each runtime schedules tasks, the memory overhead of goroutine stacks (2 KiB minimum in Go 1.22), the challenges of async‑await integration, and why Rust’s performance gains come with a fragmented ecosystem.

BirdNest Tech Talk
BirdNest Tech Talk
BirdNest Tech Talk
Go vs Rust Concurrency: Stackful vs Stackless Coroutines and Memory Impact

Both Go and Rust were designed to avoid the pitfalls of earlier languages, yet they adopt fundamentally different strategies for handling concurrency, which dramatically affect performance and developer experience.

Why concurrency matters

Modern programs frequently interact with resources such as networks or disks that may block for a noticeable period. Blocking the entire program wastes hardware resources, so languages provide mechanisms to keep the CPU busy while I/O is pending.

Task abstraction

A task is a unit of computation that can be executed concurrently; multiple functions may be processed at the same time, though not necessarily on separate CPU cores.

In Go, a new task is created with the go keyword:

go doSomething()
go doAnotherThing()

In Rust, the equivalent is the tokio::spawn function:

tokio::spawn(async move {
    do_something().await
});

tokio::spawn(async move {
    do_another_thing().await
});

Runtime

The runtime’s job is to manage and schedule these tasks to achieve efficient hardware utilization.

Go’s runtime is built into the language and cannot be swapped out (except by using a completely different compiler such as TinyGo). Rust, by contrast, does not ship a runtime; developers must explicitly add one, most commonly Tokio.

Stackful coroutines (Go)

Go uses a stackful, green‑thread model (M:N threading). The runtime manages lightweight threads and schedules them onto available OS threads. Each goroutine has its own stack, which the runtime can grow dynamically.

Two main drawbacks arise:

Each goroutine consumes a minimum of 2 KiB of memory (Go 1.22). Ten thousand concurrent goroutines therefore require at least 20 MiB.

The runtime must fully control stack layout, making interoperation with external C functions cumbersome; this is why CGO calls typically cost 30–75 ns.

Stackless coroutines (Rust)

Rust adopts a stackless approach. A Future is a plain struct implementing the Future trait; each .await chain is compiled into a large state machine without a dedicated stack.

Async pitfalls

Languages like Python or C# suffer from the “function coloring” problem: synchronous functions cannot call asynchronous ones and vice‑versa, leading to ecosystem fragmentation and hard‑to‑interoperate libraries (e.g., a library libA that lacks async support).

Rust exacerbates this because the standard library lacks async equivalents for many sync APIs (e.g., no async read for whole‑file reads), and different runtimes (Tokio, async‑std, etc.) are not interchangeable.

Go solves these issues by making all I/O appear synchronous; the compiler and runtime automatically insert the necessary await points, which is transparent to the programmer, though it incurs memory and CPU overhead.

Conclusion

Rust’s stackless model can extract maximum machine performance, but the fragmented ecosystem—unstable infrastructure, duplicated effort, and lack of a unified runtime—hampers adoption.

For deeper insight into concurrency and runtime internals, see the referenced articles on cooperative vs. preemptive scheduling and Tokio’s inner workings.

References

[1] Function coloring problem: https://journal.stuffwithstuff.com/2015/02/01/what-color-is-your-function

[2] "Async Rust: Cooperative vs. Preemptive Scheduling": https://kerkour.com/cooperative-vs-preemptive-scheduling

[3] "Async Rust: What Is a Runtime? Tokio Internals": https://kerkour.com/rust-async-await-what-is-a-runtime

[4] "Why Choose Async Rust?": https://without.boats/blog/why-async-rust

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

RustGoRuntimeMemoryAsynccoroutines
BirdNest Tech Talk
Written by

BirdNest Tech Talk

Author of the rpcx microservice framework, original book author, and chair of Baidu's Go CMC committee.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.