Async crate comparison

From Rust Community Wiki
Jump to navigation Jump to search

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

Asynchronous Crates[edit | edit source]

Futures[edit | edit source]

The Cargo vec.svgfutures 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.

Becase Cargo vec.svgfutures is slow to compile, some developers are maintaining subsets of it called Cargo vec.svgfutures-lite and Cargo vec.svgfutures-micro .

Tokio[edit | edit source]

Cargo vec.svgTokio is the oldest and most widely used asynchronous runtime, surpassing all other runtimes in usage combined.[1] 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 Cargo vec.svgmio and the primary maintainer of Tokio today).

async-std[edit | edit source]

Cargo vec.svgasync-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 Cargo vec.svgfutures crate.

smol[edit | edit source]

Cargo vec.svgsmol 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 Cargo vec.svgasync-task , Cargo vec.svgasync-io , and Cargo vec.svgmultitask . 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.

  • An executor is started by smol::run .
  • Smol uses I/O traits from the Cargo vec.svgfutures crate.

Other utilies live in Cargo vec.svgasync-channel , Cargo vec.svgasync-fs , Cargo vec.svgasync-net , Cargo vec.svgasync-process , Cargo vec.svgasync-mutex , Cargo vec.svgasync-lock and Cargo vec.svgasync-rwlock .

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.

Actix[edit | edit source]

Cargo vec.svgactix is an actor system created in 2017 with a focus on a type-safe actor model and extensibility. Actix uses Tokio under the hood.

embrio[edit | edit source]

A runtime intended for embedded systems, developed by Wim Looman since 2018.Template:Citation needed

Bastion[edit | edit source]

Cargo vec.svgBastion pivots towards supervision and fault tolerance in the spirit of Erlang. Conceived in July 2019 by Mahmut Bulut.

Comparison of Async Ecosystems[edit | edit source]

There are three main async ecosystems in use:

  • Cargo vec.svgtokio , which is the oldest one. It is one large crate made lighter with feature flags.
  • Cargo vec.svgasync-std , which is newer. It changed to use Smol's executor (Cargo vec.svgasync-executor ) once Smol was released. It is also one large crate.
  • Cargo vec.svgsmol , 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 Cargo vec.svgfutures , which isn't an ecosystem like Tokio or async-std but contains many useful future-related types.

Category Description std Equivalent Cargo vec.svgTokio Cargo vec.svgasync-std Cargo vec.svgsmol and similar Cargo vec.svgfutures
Runtimes Main functions and test functions fn main(), #[test] #[tokio::main], #[tokio::test] Cargo vec.svgasync-attributes , which is reexported from async-std Cargo vec.svgsmol-potat N/A
Start the runtime manually N/A tokio::runtime::Runtime async_std::task::block_on Cargo vec.svgasync-executor /smol::run futures::executor::block_on
Spawn a task which doesn't block spawnThis links to official Rust documentation tokio::spawn async_std::task::spawn async_executor::Task::spawn futures::executor::ThreadPool
Spawn a task which can block tokio::task::spawn_blocking async_std::task::spawn_blocking Cargo vec.svgblocking N/A
Spawn a !Send task locally N/A tokio::task::spawn_local async_std::task::spawn_local async_executor::Task::local futures::executor::LocalSpawner
Time Sleep std::thread::sleepThis links to official Rust documentation tokio::time::delay_for async_std::task::sleep async_io::Timer::after N/A
Time Interval N/A tokio::time::interval async_std::stream::interval async_io::Timer::interval N/A
Timeout std::thread::park_timeoutThis links to official Rust documentation tokio::time::timeout async_std::io::timeout/async_std::future::timeout future.or(async { Timer::after(timeout).await; None }) N/A
IO IO std::ioThis links to official Rust documentation tokio::io async_std::io Cargo vec.svgasync-io /futures_lite::io futures::io
Networking std::netThis links to official Rust documentation tokio::net async_std::net Cargo vec.svgasync-net N/A
Filesystem std::fsThis links to official Rust documentation tokio::fs async_std::fs Cargo vec.svgasync-fs N/A
OS Processes std::processThis links to official Rust documentation tokio::process async_std::process Cargo vec.svgasync-process N/A
Signal handling N/A tokio::signal N/A Cargo vec.svgasync-signal (as of now unwritten) N/A
Locks Mutex std::sync::MutexThis links to official Rust documentation tokio::sync::Mutex async_std::sync::Mutex Cargo vec.svgasync-mutex futures::lock::Mutex
RwLock std::sync::RwLockThis links to official Rust documentation tokio::sync::RwLock async_std::sync::RwLock Cargo vec.svgasync-rwlock N/A
Channels Oneshot N/A tokio::sync::oneshot N/A Cargo vec.svgasync-oneshot /Cargo vec.svgasync-channel with bounded(1) futures::channel::oneshot
MPSC std::sync::mpscThis links to official Rust documentation tokio::sync::mpsc async_std::sync::channel Cargo vec.svgasync-channel / Cargo vec.svgasync-watch futures::channel::mpsc
SPMC N/A tokio::sync::watch N/A
MPMC tokio::sync::broadcast N/A

Low Level Crates[edit | edit source]

Mio[edit | edit source]

Cargo vec.svgmio 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[edit | edit source]

Cargo vec.svgpolling offers a portable interface to epoll/kqueue/wepoll. It was created as a simpler alternative to [[mio|Cargo vec.svgmio ]] and is used by Cargo vec.svgasync-io , which is the basis for async I/O in async-std and 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[edit | edit source]

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

Cargo vec.svgringbahn is a safe and convenient API for using io_uring from Rust idiomatically.

Cargo vec.svgrio 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.

Historically significant[edit | edit source]

Cargo vec.svgrotor[edit | edit source]

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

References[edit | edit source]

  1. Tokio on crates.io: downloads, reverse dependencies