Tokio (software)

From Wikipedia, the free encyclopedia
Jump to navigation Jump to search
Tokio
Original authorCarl Lerche
Initial releaseDecember 23, 2020; 5 years ago (2020-12-23)
Repository
  • {{URL|example.com|optional display text}}Lua error in Module:EditAtWikidata at line 29: attempt to index field 'wikibase' (a nil value).
Written inRust
Engine
    Lua error in Module:EditAtWikidata at line 29: attempt to index field 'wikibase' (a nil value).
    Operating systemWindows, Linux, macOS, FreeBSD, WebAssembly
    TypeAsynchronous runtime
    LicenseMIT License
    Websitetokio.rs

    Lua error in mw.title.lua at line 392: bad argument #2 to 'title.new' (unrecognized namespace name 'Portal'). 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.[1][2][3]

    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.

    History

    [edit | edit source]

    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.[4][5][6] The name "Tokio" is derived from Tokyo and mio, and the Tokio logo vaguely resembles the city emblem of Tokyo.[7] The preliminary version of Tokio was released in January 2017,[8] followed by a full release in December 2020.[9][10] In 2017, Tokio received a grant from the Mozilla Open Source Support fund.[11] In April 2021, Tokio funded its first paid contributor, Alice Ryhl, for her work both developing the project and assisting its users.[12][13]

    While Rust has supported asynchronous functions since version 1.39, released in November 2019,[14] it provides no facilities to execute them, requiring an external runtime for that purpose.[15] Tokio provides a runtime that uses a multi-threaded work stealing scheduler.[9] Rust's futures are lazily evaluated, requiring functions to call .await before they do any work.[16] 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.[17]

    Users of Tokio include the development teams behind Discord and AWS Lambda.[9] The JavaScript and TypeScript runtime Deno uses Tokio under the hood, in comparison to the JavaScript runtime Node.js, which uses the libuv library.[18]

    Features

    [edit | edit source]

    Runtime

    [edit | edit source]

    Tokio allows for the execution of asynchronous functions in Rust through its built-in runtime, which may be initialized via the #[tokio::main] macro.[17] For example:

    use std::error::Error;
    
    #[tokio::main]
    async fn main() -> Result<(), Box<dyn Error>> {
        let url = "https://en.wikipedia.org/";
        let text = 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:

    use std::error::Error;
    use tokio::io::{AsyncBufReadExt, AsyncWriteExt, BufReader};
    use tokio::net::TcpListener;
    
    #[tokio::main]
    async fn main() -> Result<(), Box<dyn Error>> {
        // Run a server on port 8080.
        let listener = TcpListener::bind("localhost:8080").await?;
    
        loop {
            // Wait for a new connection from a client.
            let (mut stream, _remote_addr) = listener.accept().await?;
    
            // Spawn a new asynchronous task to handle the connection.
            tokio::spawn(async move {
                let (reader, mut writer) = stream.split();
                let mut reader = 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.[19] 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.

    Asynchronous I/O and timers

    [edit | edit source]

    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.[20]

    Synchronization primitives

    [edit | edit source]

    Tokio also provides several generic synchronization primitives suitable for use in an asynchronous context, including locks, semaphores, barriers and channels.[21] Unlike the I/O and timer primitives, these work even outside of the runtime context.[22]

    Blocking thread pool

    [edit | edit source]

    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.[23] 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.[24] 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).[25]

    References

    [edit | edit source]
    1. ^ Lua error in Module:Citation/CS1/Configuration at line 2172: attempt to index field '?' (a nil value).
    2. ^ Lua error in Module:Citation/CS1/Configuration at line 2172: attempt to index field '?' (a nil value).
    3. ^ Lua error in Module:Citation/CS1/Configuration at line 2172: attempt to index field '?' (a nil value).
    4. ^ Lua error in Module:Citation/CS1/Configuration at line 2172: attempt to index field '?' (a nil value).
    5. ^ Lua error in Module:Citation/CS1/Configuration at line 2172: attempt to index field '?' (a nil value).
    6. ^ Lua error in Module:Citation/CS1/Configuration at line 2172: attempt to index field '?' (a nil value).
    7. ^ Lua error in Module:Citation/CS1/Configuration at line 2172: attempt to index field '?' (a nil value).
    8. ^ Lua error in Module:Citation/CS1/Configuration at line 2172: attempt to index field '?' (a nil value).
    9. ^ a b c Lua error in Module:Citation/CS1/Configuration at line 2172: attempt to index field '?' (a nil value).
    10. ^ Lua error in Module:Citation/CS1/Configuration at line 2172: attempt to index field '?' (a nil value).
    11. ^ Lua error in Module:Citation/CS1/Configuration at line 2172: attempt to index field '?' (a nil value).
    12. ^ Lua error in Module:Citation/CS1/Configuration at line 2172: attempt to index field '?' (a nil value).
    13. ^ Lua error in Module:Citation/CS1/Configuration at line 2172: attempt to index field '?' (a nil value).
    14. ^ Lua error in Module:Citation/CS1/Configuration at line 2172: attempt to index field '?' (a nil value).
    15. ^ Lua error in Module:Citation/CS1/Configuration at line 2172: attempt to index field '?' (a nil value).
    16. ^ Lua error in Module:Citation/CS1/Configuration at line 2172: attempt to index field '?' (a nil value).
    17. ^ a b Lua error in Module:Citation/CS1/Configuration at line 2172: attempt to index field '?' (a nil value).
    18. ^ Lua error in Module:Citation/CS1/Configuration at line 2172: attempt to index field '?' (a nil value).
    19. ^ Lua error in Module:Citation/CS1/Configuration at line 2172: attempt to index field '?' (a nil value).
    20. ^ Lua error in Module:Citation/CS1/Configuration at line 2172: attempt to index field '?' (a nil value).
    21. ^ Lua error in Module:Citation/CS1/Configuration at line 2172: attempt to index field '?' (a nil value).
    22. ^ Lua error in Module:Citation/CS1/Configuration at line 2172: attempt to index field '?' (a nil value).
    23. ^ Lua error in Module:Citation/CS1/Configuration at line 2172: attempt to index field '?' (a nil value).
    24. ^ Lua error in Module:Citation/CS1/Configuration at line 2172: attempt to index field '?' (a nil value).
    25. ^ Lua error in Module:Citation/CS1/Configuration at line 2172: attempt to index field '?' (a nil value).
    [edit | edit source]