Tokio | |
---|---|
![]() | |
Original author(s) | Carl Lerche |
Initial release | December 23, 2020 |
Stable release | |
Repository | |
Written in | Rust |
Operating system | macOS, Windows, Linux, FreeBSD, WebAssembly |
Type | Asynchronous runtime |
License | MIT License |
Website | tokio |
Tokio is a software library for the Rust programming language. It provides a runtime and functions that enable the use of asynchronous I/O, allowing for concurrency in regards to task completion. [2] [3] [4]
Tokio was released in August 2016 for Rust, a general-purpose programming language. Developed by Carl Lerche, Tokio began as a network application framework and supports features such as socket listening and broadcasting, allowing messages to be transferred between computers.
Tokio began in August 2016 by Carl Lerche as a network application framework for Rust built on futures, allowing for network-based middleware and a non-blocking, or asynchronous, implementation of readiness interest to the reactor. Tokio was inspired by Finagle, a Scala-based asynchronous remote procedure call (RPC) system developed at Twitter for Java virtual machines (JVM), allowing distributed systems to communicate within a JVM. Tokio utilizes the lower-level Rust crate mio
, itself using system calls such as epoll (Linux), kqueue (FreeBSD), and the input/output completion port (IOCP) API (Windows). For Linux it can also use io_uring via tokio-uring. [5] [6] [7] The name "Tokio" is derived from Tokyo and mio. [8] The preliminary version of Tokio was released in January 2017, [9] followed by a full release in December 2020. [10] [11] In 2017, Tokio received a grant from the Mozilla Open Source Support fund. [12] In April 2021, Tokio funded its first paid contributor, Alice Ryhl, for her work both developing the project and assisting its users. [13] [14]
While Rust has supported asynchronous functions since version 1.39, released in November 2019, [15] it provides no facilities to execute them, requiring an external runtime for that purpose. [16] Tokio provides a runtime that uses a multi-threaded work stealing scheduler. [10] Rust's futures are lazily evaluated, requiring functions to call .await
before they do any work. [17] When .await
is invoked, Tokio's runtime may pause the original future until its I/O completes, and unpauses a different task that is ready for further processing. [18]
Users of Tokio include the development teams behind Discord and AWS Lambda. [10] The JavaScript and TypeScript runtime Deno uses Tokio under the hood, in comparison to the JavaScript runtime Node.js, which uses the libuv library. [19]
Tokio allows for the execution of asynchronous functions in Rust through its built-in runtime, which may be initialized via the #[tokio::main]
macro. [18] For example:
#[tokio::main]asyncfnmain()->Result<(),Box<dynstd::error::Error>>{leturl="https://en.wikipedia.org/";lettext=reqwest::get(url).await?.text().await?;println!("{}",text);Ok(())}
Here, the reqwest
crate is used to request the HyperText Markup Language (HTML) for English Wikipedia. After reqwest::get
is called to initialize the asynchronous request, .await
will hand over control to the runtime, which then drives all the I/O operations of the request to completion before resuming the main
function after the .await
.
A simple example of a TCP echo server is as follows:
usetokio::io::{AsyncBufReadExt,AsyncWriteExt,BufReader};usetokio::net::TcpListener;#[tokio::main]asyncfnmain()->Result<(),Box<dynstd::error::Error>>{// Run a server on port 8080.letlistener=TcpListener::bind("localhost:8080").await?;loop{// Wait for a new connection from a client.let(mutstream,_remote_addr)=listener.accept().await?;// Spawn a new asynchronous task to handle the connection.tokio::spawn(asyncmove{let(reader,mutwriter)=stream.split();letmutreader=BufReader::new(reader);// While there is data to be read from the stream…while!reader.fill_buf().await.unwrap().is_empty(){// Write the data back.writer.write_all(reader.buffer()).await.unwrap();}});}}
This code makes use of the tokio::spawn
function to create an asynchronous task (implemented as a stackless coroutine), allowing each connection to be handled separately in the same process, as the runtime ensures that tasks run in the background automatically. [20] Importantly however, the runtime multiplexes the tasks’ execution on a single thread pool (whose size is by default equal to the number of processors on the system), and so in comparison to the approach of spawning a separate thread for each task, fewer resources are consumed.
Tokio provides several I/O and timing primitives that work natively inside its runtime. The TcpListener
structure used above contains a Transmission Control Protocol (TCP) socket listener that is registered with the runtime, allowing it to be used asynchronously; similarly, the tokio::time::sleep
function can be used to suspend a task’s execution for a certain duration of time, and again this is implemented by registration with the runtime. [21]
Tokio also provides several generic synchronization primitives suitable for use in an asynchronous context, including locks, semaphores, barriers and channels. [22] Unlike the I/O and timer primitives, these work even outside of the runtime context. [23]
To facilitate interopability with traditional synchronous code, Tokio provides as part of its runtime a thread pool on which synchronous I/O operations may run. [24] In particular, tokio::task::spawn_blocking
creates a task which runs in this pool, and is allowed to perform blocking operations—this is unlike tokio::spawn
, which may only run asynchronous code. [25] For example, this is used to implement filesystem operations, as many platforms do not provide native asynchronous filesystem APIs (an exception to this is Linux’s io_uring
, however support for this exists only in the external tokio_uring
library and is not yet built in). [26]
{{cite book}}
: CS1 maint: location missing publisher (link){{cite book}}
: CS1 maint: location missing publisher (link)