跳到主要内容

crate tokio

搜索

crate tokio 

源代码
展开描述

用于编写可靠的网络应用程序而不影响速度的运行时。

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

指南级文档可在官网上找到。

§Tokio 概览

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

最简单的上手方式是启用所有特性。请通过启用 full 特性标志来实现:

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

§编写应用程序

Tokio 非常适合编写应用程序,对于大多数用户来说,不需要过于担心应该选择哪些特性。如果你不确定,我们建议使用 full,以确保在构建应用程序时不会遇到任何阻碍。

§示例

本示例展示使用 Tokio 最快速的上手方法。

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

§编写库

作为库的作者,你的目标应该是提供基于 Tokio 的最轻量级 crate。为此,你应该确保只启用你需要的特性。这样用户就可以使用你的 crate,而无需启用不必要的特性。

§示例

本示例展示对于一个只需要 tokio::spawn 并使用 TcpStream 的库,应当如何引入特性。

tokio = { version = "1", features = ["rt", "net"] }

§使用任务

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

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

tokio::task 模块仅在启用了 “rt” 特性标志时可用。

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

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

tokio::sync 模块仅在启用了 “sync” 特性标志时可用。

tokio::time 模块提供了跟踪时间和调度工作的工具。这包括为任务设置超时、 将工作休眠到将来某个时间再运行,或以固定间隔重复执行某个操作的函数。

要使用 tokio::time,必须启用 “time” 特性标志。

最后,Tokio 提供了一个用于执行异步任务的运行时。大多数应用程序可以使用 #[tokio::main] 宏来在 Tokio 运行时上运行它们的代码。但是,该宏只提供基本的配置选项。作为替代方案,tokio::runtime 模块提供了更强大的 API 来配置和管理运行时。如果 #[tokio::main] 宏不能满足你的需求,应当使用该模块。

使用运行时需要 “rt” 或 “rt-multi-thread” 特性标志,分别用于启用当前线程的单线程调度器多线程 调度器。详情请参阅runtime 模块文档。此外,“macros” 特性 标志会启用 #[tokio::main]#[tokio::test] 属性。

§CPU 密集型任务与阻塞代码

Tokio 能够通过在线程上反复切换当前正在运行的任务,在少量线程上并发运行大量任务。但是,这种切换只能发生在 .await 处,因此长时间无法到达 .await 的代码会阻止其他任务运行。为了解决这一问题,Tokio 提供了两种线程:核心线程和阻塞线程。

核心线程是所有异步代码运行的地方,Tokio 默认会为每个 CPU 核心派生一个核心线程。你可以使用环境变量 TOKIO_WORKER_THREADS 来覆盖默认值。

阻塞线程按需派生,可用于运行那些否则会阻塞其他任务运行的 阻塞代码。它们在一段时间内未被使用时会被保留,该时间可以通过 thread_keep_alive 进行配置。由于 Tokio 不可能像对异步代码那样换出阻塞任务,阻塞线程数量的上限非常大。这些限制可以在 Builder 上配置。

要派生一个阻塞任务,应当使用 spawn_blocking 函数。

#[tokio::main]
async fn main() {
    // 这段代码运行在核心线程上。

    let blocking_task = tokio::task::spawn_blocking(|| {
        // 这段代码运行在阻塞线程上。
        // 在这里阻塞是允许的。
    });

    // 我们可以像这样等待阻塞任务完成:
    // 如果阻塞任务 panic,下面的 unwrap 将传播该 panic。
    blocking_task.await.unwrap();
}

如果你的代码是 CPU 密集型的,并且希望限制用于运行它的线程数量,则应使用专用于 CPU 密集型任务的单独线程池。例如,可以考虑使用 rayon 库来处理 CPU 密集型任务。也可以创建一个专用于 CPU 密集型任务的额外 Tokio 运行时,但如果这样做,需要小心,让该额外运行时运行 CPU 密集型任务,因为在该运行时上运行 I/O 密集型任务时表现会很差。

提示:如果使用 rayon,可以在 rayon 任务完成时使用 oneshot 通道将结果发送回 Tokio。

§异步 I/O

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

tokio::io 模块提供了 Tokio 的异步核心 I/O 原语,即 AsyncReadAsyncWriteAsyncBufRead 这些 trait。此外,当启用了 “io-util” 特性标志时,它还提供了用于处理这些 trait 的组合子和函数,作为 std::io 的异步对应物。

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::io::{AsyncReadExt, AsyncWriteExt};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let 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];

            // 在循环中,从套接字读取数据并将其写回。
            loop {
                let n = match socket.read(&mut buf).await {
                    // 套接字已关闭
                    Ok(0) => return,
                    Ok(n) => n,
                    Err(e) => {
                        eprintln!("failed to read from socket; err = {:?}", e);
                        return;
                    }
                };

                // 将数据写回
                if let Err(e) = socket.write_all(&buf[0..n]).await {
                    eprintln!("failed to write to socket; err = {:?}", e);
                    return;
                }
            }
        });
    }
}

§特性标志

Tokio 使用一组特性标志来减少编译代码量。可以只启用其中某些特性而不启用其他特性。默认情况下,Tokio 不会启用任何特性,但允许你为用例启用一个子集。下面是可用特性标志的列表。你可能还会注意到在每个函数、结构体和 trait 上方会列出使用该项所需的一个或多个特性标志。如果你是 Tokio 的新手,建议使用 full 特性标志,它会启用所有公开 API。但请注意,这会引入许多你可能不需要的额外依赖。

  • full:启用下面列出的所有特性,test-util 和不稳定特性除外。
  • rt:启用 tokio::spawn、当前线程调度器 以及非调度器相关的工具。
  • rt-multi-thread:启用较重的、多线程的工作窃取调度器。
  • io-util:启用基于 I/O 的 Ext trait。
  • io-std:启用 StdoutStdinStderr 类型。
  • net:启用 tokio::net 中的类型,如 TcpStreamUnixStreamUdpSocket,以及(类 Unix 系统上的)AsyncFd 和(FreeBSD 上的)PollAio
  • time:启用 tokio::time 中的类型,并允许调度器启用 内置定时器。
  • process:启用 tokio::process 中的类型。
  • macros:启用 #[tokio::main]#[tokio::test] 宏。
  • sync:启用所有 tokio::sync 类型。
  • signal:启用所有 tokio::signal 类型。
  • fs:启用 tokio::fs 类型。
  • test-util:启用 Tokio 运行时的测试相关基础设施。
  • parking_lot:作为一种潜在优化,内部使用 [parking_lot] crate 的 同步原语。此外,该依赖也是在 const 上下文中构造 我们某些原语所必需的。MSRV 可能会根据所使用 的 [parking_lot] 版本而提高。

注意:AsyncReadAsyncWrite trait 不需要任何特性,始终可用。

§不稳定特性

某些特性标志仅在指定了 tokio_unstable 标志时才可用:

  • tracing:启用 tracing 事件。
  • io-uring:启用 io-uring(仅限 Linux)。
  • taskdump:启用 taskdump(仅限 Linux)。

同样,此标志可以访问不稳定的 API。

此标志启用不稳定特性。这些特性的公开 API 可能会在 1.x 版本中发生破坏性变更。要启用这些特性,在编译时必须向 rustc 传递 --cfg tokio_unstable 参数。这样做是为了显式选择加入可能违反 semver 约定的特性,因为 Cargo 尚不直接支持此类选择加入

可以在项目的 .cargo/config.toml 文件中指定它:

[build]
rustflags = ["--cfg", "tokio_unstable"]
[build]不是放在 Cargo.toml 文件中, 而必须放在 Cargo 配置文件 .cargo/config.toml 中。

或者,可以通过环境变量来指定它:

## Many *nix shells:
export RUSTFLAGS="--cfg tokio_unstable"
cargo build
## Windows PowerShell:
$Env:RUSTFLAGS="--cfg tokio_unstable"
cargo build

§支持的平台

Tokio 目前保证支持以下平台:

  • Linux
  • Windows
  • Android(API 级别 21)
  • macOS
  • iOS
  • FreeBSD

Tokio 将在未来继续支持这些平台。但是,未来的版本可能会更改一些要求,例如 Linux 上所需的最低 libc 版本、Android 上的 API 级别,或受支持的 FreeBSD 版本。

除上述平台外,Tokio 旨在能在 mio crate 支持的所有平台上运行。可以在 mio 的文档中找到更长的平台列表。但是,这些额外的平台在未来可能会变得不再受支持。

请注意,Wine 被视为与 Windows 不同的平台。有关 Wine 支持的更多信息,请参阅 mio 的文档。

§WASM support

Tokio 对 WASM 平台有一些有限的支持。在不使用 tokio_unstable 标志的情况下,支持以下特性:

  • sync
  • macros
  • io-util
  • rt
  • time

启用任何其他特性(包括 full)都会导致编译失败。

time 模块仅在支持定时器的 WASM 平台(例如 wasm32-wasi)上可用。在不支持定时器的 WASM 平台上使用时,相关的时间函数会 panic。

还需注意,如果运行时无限期地空闲,它会立即 panic,而不是永远阻塞。在不支持时间的平台上,这意味着运行时永远不能以任何方式处于空闲状态。

§Unstable WASM support

Tokio 还不稳定地支持一些额外的 WASM 特性。这需要使用 tokio_unstable 标志。

使用此标志可以在 wasm32-wasi 目标上使用 tokio::net。但是,并非所有方法都可在网络类型上使用,因为 WASI 目前不支持从 WASM 内部创建新套接字。因此,目前必须通过 FromRawFd trait 来创建套接字。

重新导出§

pub use task::spawn;

模块§

io
异步 I/O 功能的 trait、辅助类型和类型定义。
net
tokio 的 TCP/UDP/Unix 绑定。
runtime
Tokio 运行时。
stream
由于 Stream trait 进入 std 的时间晚于 Tokio 1.0 发布, Tokio 的大多数流相关工具已迁移到 tokio-stream crate 中。
sync
用于异步上下文的同步原语。
task
异步的绿色线程。
time
用于跟踪时间的工具。

§

pin
在栈上固定一个值。
task_local
声明一个类型为 tokio::task::LocalKey 的新任务局部键。