Rust's approach to bringing async code into the language is novel, in that instead of packaging the async system with the language, such as Golang's approach of providing in-built goroutinesTemplate:Citation needed, it presents an interface to be used by independent crate developers to implement the async runtime for a given process. It also separates the job of the executor or runtime (which polls the futures) and the reactor (which tells the executor when the futures should be polled). Out of this interface, a number of projects have emerged.
Crates that provide both a runtime and IO abstractions often have their IO depend on the runtime. This can make it difficult to write runtime-agnostic code.Template:Citation needed
futures crate provides common abstractions for asynchronous code. It defined the original
Future trait before it was moved into the standard library, and now provides many useful runtime-agnostic abstractions and tools such as asynchronous streams, sinks, locks and IO traits. It comes with a basic executor.
Gradually, some of the features that the futures crate provides will be moved into the standard library.
Tokio is the oldest and most widely used asynchronous runtime, surpassing all other runtimes in usage combined. It provides a runtime and IO, as well as useful asynchronous utilities including process spawning, signal handling, channels, locks, and timers. It was created in 2016 by Aaron Turon, Alex Crichton, and Carl Lerche (who is the author of
mio and the primary maintainer of Tokio today).
- Tokio's I/O is based on mio.
- It supports several executors, configurable by user. The runtime is started manually by the user using either the
tokio::runtimemodule, or with the
- Tokio uses custom IO traits like
AsyncWrite, requiring a compatibility layer to integrate with
async-std is the first stable async runtime and the first to adopt the async/await syntax. It was published in August 2019 by Yoshua Wuyts and Stjepan Glavina with the aim of developing a full runtime whose API mirrors Rust’s standard library. It provides an executor, async IO, and many asynchronous utilities.
- There is a single global runtime, which is started on first use.
- async-std uses I/O traits from the
smol is Stjepan Glavina’s second runtime, released in April 2020. Its core selling points are small size and fast compilation. Much of the complexity is abstracted into individual crates like
async-io , and
multitask . Unlike async-std and Tokio, which provide their own async networking types, smol provides a single type:
Async<T>, which can wrap any standard networking type to make it asynchronous.
Smol is more a collection of independent async crates rather than a single runtime itself. This collection makes it easy to build new runtimes. A lot of them have now been adopted by async-std.
A runtime intended for embedded systems, developed by Wim Looman since 2018.Template:Citation needed
Bastion pivots towards supervision and fault tolerance in the spirit of Erlang. Conceived in July 2019 by Mahmut Bulut.
Comparison of Async Ecosystems
There are three main async ecosystems in use:
tokio, which is the oldest one. It is one large crate made lighter with feature flags.
async-std, which is newer. It changed to use Smol's executor (
async-executor) once Smol was released. It is also one large crate.
smol, which is the newest and is split up into many many different crates. Lots of the crates listed in this column have types reexported by the smol crate, but some are completely independent.
Additionally, this table lists
futures , which isn't an ecosystem like Tokio or async-std but contains many useful future-related types.
Low Level Crates
mio is a crate for low-level cross-platform non-blocking IO. In the standard library, all IO is called synchronously and blocks the thread it is called from — this means that only one IO task can be performed at once per thread. Mio provides an API to specify the IO tasks to wait for and a way to block until the first one has finished, allowing a large number of IO tasks to run at once. It is used for the underlying implementation of many IO reactors including Tokio.
polling offers a portable interface to epoll/kqueue/wepoll. It was created as a simpler alternative to [[mio|
mio ]] and is used by
async-io , which is the basis for async I/O in
smol. Supported platforms are Linux, Android, macOS, iOS, FreeBSD, NetBSD, OpenBSD, DragonFly BSD, illumos, Solaris, and Windows. Events are triggered in the 'oneshot' fashion.Template:Citation needed
io_uring is a new completion based asynchronous IO API for Linux. It is still new and support in Rust is highly experimental, but it promises better throughput than traditional Linux async I/O approaches such as
epoll, especially for filesystem IO.Template:Citation needed
ringbahn is a safe and convenient API for using
io_uring from Rust idiomatically.
rio is another low-level crate targeting
io_uring, however, usage of it is highly discouraged due to an explicit case of unsoundness (UB accessible from safe code) which the author decided not to fix at all.
The oldest asynchronous runtime ever developed for Rust which included its own vision of
Future trait. Eventually deprecated by the Tokio stack.Template:Citation needed