6个版本

0.2.16 2020年1月30日
0.2.15 2020年1月23日

异步中排名1327

MIT许可

1.5MB
23K SLoC

不要使用


lib.rs:

一个用于编写可靠、异步和精简应用程序的运行时。

Tokio是一个事件驱动的、非阻塞I/O平台,用于使用Rust编程语言编写异步应用程序。在较高层面上,它提供了一些主要组件

  • 用于处理异步任务的各种工具,包括同步原语和通道,以及超时、延迟和间隔。
  • 执行异步I/O的API,包括TCP和UDP套接字、文件系统操作以及进程和信号管理。
  • 执行异步代码的运行时,包括任务调度器、基于操作系统事件队列(epoll、kqueue、IOCP等)的I/O驱动器以及高性能计时器。

指南级别的文档可在网站上找到。

Tokio之旅

Tokio由多个模块组成,这些模块提供了实现Rust中异步应用程序所需的各种功能。在本节中,我们将简要浏览Tokio,总结主要API及其用途。

开始的最简单方法是启用所有功能。通过启用full功能标志来完成此操作

tokio = { version = "0.2", features = ["full"] }

功能标志

Tokio 使用一系列 功能标志 来减少编译后的代码量。可以选择只启用某些功能。默认情况下,Tokio 不启用任何功能,但允许用户根据其用例启用子集。以下是一份可用的功能标志列表。您可能还会注意到,在每一个函数、结构和特质上方,都有一个需要启用该项目的功能标志集合。如果您是 Tokio 的初学者,建议您使用 full 功能标志,这将启用所有功能。但请注意,这将引入许多您可能不需要的额外依赖项。

  • full:启用所有 Tokio 功能,所有 API 都将可用。
  • rt-core:启用 tokio::spawn 和基本的(单线程)调度器。
  • rt-threaded:启用较重的、多线程的、基于工作窃取的调度器。
  • rt-util:启用非调度器工具。
  • io-driver:启用基于 mio 的 IO 驱动器。
  • io-util:启用基于 IO 的 Ext 特质。
  • io-std:启用 StdoutStdinStderr 类型。
  • net:启用 tokio::net 类型,例如 TcpStreamUnixStreamUdpSocket
  • tcp:启用所有 tokio::net::tcp 类型。
  • udp:启用所有 tokio::net::udp 类型。
  • uds:启用所有 tokio::net::unix 类型。
  • time:启用 tokio::time 类型,并允许调度器启用内置计时器。
  • process:启用 tokio::process 类型。
  • macros:启用 #[tokio::main]#[tokio::test] 宏。
  • sync:启用所有 tokio::sync 类型。
  • stream:为 Tokio 内部的类型启用可选的 Stream 实现。
  • signal:启用所有 tokio::signal 类型。
  • fs:启用 tokio::fs 类型。
  • dns:启用异步 tokio::net::ToSocketAddrs
  • test-util:启用 Tokio 运行时的基于测试的基础设施。
  • blocking:启用 block_in_placespawn_blocking

注意:AsyncReadAsyncWrite 不需要任何功能,默认情况下已启用。

编写应用程序

Tokio非常适合编写应用程序,大多数用户在这种情况下不必过多担心应该选择哪些功能。如果您不确定,我们建议选择full以确保在构建应用程序时不会遇到任何障碍。

示例

此示例展示了使用Tokio入门的最快方式。

tokio = { version = "0.2", features = ["full"] }

编写库

作为库的作者,您的目标应该是提供基于Tokio的最轻量级的crate。为了实现这一点,您应该确保只启用所需的特性。这允许用户在不需要启用不必要功能的情况下选择您的crate。

示例

此示例展示了如何为仅需要tokio::spawn和使用TcpStream的库导入功能。

tokio = { version = "0.2", features = ["rt-core", "tcp"] }

与任务协同工作

Rust中的异步程序围绕轻量级、非阻塞的执行单元任务构建。`tokio::task`模块提供了处理任务的重要工具

  • `spawn`函数和`JoinHandle`类型,分别用于在Tokio运行时调度新任务以及等待已派生任务的输出
  • 用于在异步任务上下文中运行阻塞操作的函数。

`tokio::task`模块仅在启用"rt-core"功能标志时存在。

`tokio::sync`模块包含在需要通信或共享数据时使用的同步原语。这些包括

  • 通道(`oneshot、`mpsc和`watch`),用于在任务之间发送值
  • 一个非阻塞的`Mutex`,用于控制对共享可变值的访问
  • 一个异步的`Barrier`类型,用于在多个任务在开始计算之前进行同步

`tokio::sync`模块仅在启用"syn"功能标志时存在。

`tokio::time`模块提供了跟踪时间和安排工作的实用程序。这包括设置任务超时延迟工作以在未来运行或按间隔重复操作的函数。

要使用`tokio::time`,必须启用"时间"功能标志。

最后,Tokio提供了一个运行时来执行异步任务。大多数应用程序可以使用#[tokio::main]宏在其代码上运行Tokio运行时。在需要手动控制运行时的情况下,`tokio::runtime`模块提供了配置和管理运行时的API。

使用运行时需要启用 "rt-core" 或 "rt-threaded" 功能标志,分别启用基本 单线程调度器线程池调度器。有关详细信息,请参阅 runtime 模块文档。此外,"macros" 功能标志启用 #[tokio::main]#[tokio::test] 属性。

异步 IO

除了调度和运行任务外,Tokio 还提供了您执行输入和输出所需的所有功能。

模块 tokio::io 提供了 Tokio 的异步核心 I/O 原语,包括 AsyncReadAsyncWriteAsyncBufRead 特性。此外,当启用 "io-util" 功能标志时,它还提供了处理这些特性的组合器和函数,形成 std::io 的异步对应物。当启用 "io-driver" 功能标志时,它还提供了用于实现 I/O 资源的库作者的实用工具。

Tokio 还包括执行各种类型的 I/O 和与操作系统异步交互的 API。这包括

  • tokio::net,它包含 TCPUDPUnix 域套接字 的非阻塞版本(由 "net" 功能标志启用),
  • tokio::fs,类似于 std::fs 但用于异步执行文件系统 I/O(由 "fs" 功能标志启用),
  • tokio::signal,用于异步处理 Unix 和 Windows 操作系统信号(由 "signal" 功能标志启用),
  • tokio::process,用于创建和管理子进程(由 "process" 功能标志启用)。

示例

简单的 TCP 回显服务器

use tokio::net::TcpListener;
use tokio::prelude::*;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let mut listener = TcpListener::bind("127.0.0.1:8080").await?;

    loop {
        let (mut socket, _) = listener.accept().await?;

        tokio::spawn(async move {
            let mut buf = [0; 1024];

            // In a loop, read data from the socket and write the data back.
            loop {
                let n = match socket.read(&mut buf).await {
                    // socket closed
                    Ok(n) if n == 0 => return,
                    Ok(n) => n,
                    Err(e) => {
                        eprintln!("failed to read from socket; err = {:?}", e);
                        return;
                    }
                };

                // Write the data back
                if let Err(e) = socket.write_all(&buf[0..n]).await {
                    eprintln!("failed to write to socket; err = {:?}", e);
                    return;
                }
            }
        });
    }
}

依赖项

~0.3–1MB
~16K SLoC