跳到主要内容

Crate tokio

搜索

Crate tokio 

Source
展开描述

一个用于写作可靠的网络应用程序的运行时,不以性能为价。

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

入门级文档请参阅 官网

§A Tour of Tokio

Tokio 由许多模块组成,这些模块提供在 Rust 中实现异步应用程序所必需的一系列功能。 本节将简要介绍 Tokio,概述其主要的 API 及其用法。

最简单的开始方式是启用所有特性。 只需在 Cargo.toml 中启用 full 特性标志:

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

§开发应用程序

Tokio 非常适合编写应用程序,这种情况下大多数用户 不必太担心应该选择哪些特性。如果你不确定,我们建议 使用 full,以确保在开发过程中 不会遇到任何障碍。

§Example

此示例展示了最快速使用 Tokio 的方法。

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

§开发库

作为一个库的作者,你的目标应该是提供一个基于 Tokio 的最轻量的 crate。 为了实现这一点,你应该保证只启用你需要的特性。这样用户可以在引入你的 crate 时不必启用 不必要的特性。

§Example

此示例展示如何为一个只需要 tokio::spawn 和使用 TcpStream 的库导入特性。

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

§任务的使用

Rust 中的异步程序基于轻量级、非阻塞的 执行单元,称为 taskstokio::task 模块提供了 使用任务的重要工具:

  • The spawn function and JoinHandle type, for scheduling a new task on the Tokio runtime and awaiting the output of a spawned task, respectively,
  • Functions for running blocking operations in an asynchronous task context.

tokio::task 模块只在启用了“rt” 特性标志时才存在。

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

  • channels (oneshot, mpsc, watch, and broadcast), for sending values between tasks,
  • a non-blocking Mutex, for controlling access to a shared, mutable value,
  • an asynchronous Barrier type, for multiple tasks to synchronize before beginning a computation.

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 提供了两类线程。

Core 线程是所有异步代码的运行地点,Tokio 默认会为每个 CPU 核心独产一个。 可以通过环境变量 TOKIO_WORKER_THREADS 覆盖默认值。

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

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

#[tokio::main]
async fn main() {
    // This is running on a core thread.

    let blocking_task = tokio::task::spawn_blocking(|| {
        // This is running on a blocking thread.
        // Blocking here is ok.
    });

    // We can wait for the blocking task like this:
    // If the blocking task panics, the unwrap below will propagate the
    // panic.
    blocking_task.await.unwrap();
}

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

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

§异步 I/O

除了调度和运行任务,Tokio 还提供了异步执行输入输出(I/O)操作所需的一切。

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

Tokio 还包括用于异步执行各种 I/O 并与操作系统交互的 API,包括:

  • tokio::net, which contains non-blocking versions of TCP, UDP, and Unix Domain Sockets (enabled by the “net” feature flag),
  • tokio::fs, similar to std::fs but for performing filesystem I/O asynchronously (enabled by the “fs” feature flag),
  • tokio::signal, for asynchronously handling Unix and Windows OS signals (enabled by the “signal” feature flag),
  • tokio::process, for spawning and managing child processes (enabled by the “process” feature flag).

§示例

一个简单的 TCP echo 服务器:

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];

            // 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(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;
                }
            }
        });
    }
}

§Feature flags

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

  • full: Enables all features listed below except test-util and unstable features.
  • rt: Enables tokio::spawn, the current-thread scheduler, and non-scheduler utilities.
  • rt-multi-thread: Enables the heavier, multi-threaded, work-stealing scheduler.
  • io-util: Enables the IO based Ext traits.
  • io-std: Enable Stdout, Stdin and Stderr types.
  • net: Enables tokio::net types such as TcpStream, UnixStream and UdpSocket, as well as (on Unix-like systems) AsyncFd and (on FreeBSD) PollAio.
  • time: Enables tokio::time types and allows the schedulers to enable the built-in timer.
  • process: Enables tokio::process types.
  • macros: Enables #[tokio::main] and #[tokio::test] macros.
  • sync: Enables all tokio::sync types.
  • signal: Enables all tokio::signal types.
  • fs: Enables tokio::fs types.
  • test-util: Enables testing based infrastructure for the Tokio 运行时。
  • parking_lot: As a potential optimization, use the parking_lot crate’s synchronization primitives internally. Also, this dependency is necessary to construct some of our primitives in a const context. MSRV may increase according to the parking_lot release in use.

注意:AsyncReadAsyncWrite trait 不需要任何特性,就可以使用。

§不稳定特性

有些特性标志只在指定 tokio_unstable 标志时才可用:

  • tracing: Enables tracing events.
  • io-uring: Enables io-uring (Linux only).
  • taskdump: Enables taskdump (Linux only).

同样,这个标志开启了不稳定 API 的访问权限。

这个标志启用 不稳定 特性。这些特性的公开 API 可能会在 1.x 发布中舍弃。为了启用这些特性,编译时必须将 --cfg tokio_unstable 参数传递给 rustc。 这种显式的抑入使得这些特性是明确的选择性开启, 因为 Cargo 尚未直接支持此类选择性开启

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

[build]
rustflags = ["--cfg", "tokio_unstable"]
The [build] section does not go in a Cargo.toml file. Instead it must be placed in the Cargo config file .cargo/config.toml.

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

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

§Supported platforms

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

  • Linux
  • Windows
  • Android (API level 21)
  • macOS
  • iOS
  • FreeBSD

Tokio 将未来继续支持这些平台。但是,未来的发布版本可能会改变以下要求: Linux 上最低所需的 libc 版本、Android 上的 API 等级,或者支持的 FreeBSD 发布版本。

限于以上平台,Tokio 计划支持 mio crate 所支持的所有平台。 可以在 mio 的文档 中查看更长的列表。 但这些额外的平台在未来可能会不再受支持。

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

§WASM 支持

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

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

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

time 模块只会在支持定时器的 WASM 平台上有效 (例如 wasm32-wasi)。在不支持定时器的 WASM 平台上使用定时函数会触发 panic。

还要注意,如果运行时被無限别闲置,它会立刻 panic 而非永远阻塞。 在不支持时间的平台上,这意味着运行时永远不会停滚。

§不稳定的 WASM 支持

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

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

重新导出§

pub use task::spawn;

模块§

fs
异步文件工具。
io
用于异步 I/O 功能的 trait(特征标志)、辅助函数和类型定义。
net
tokio 的 TCP/UDP/Unix 绑定。
process
Tokio 的异步进程管理实现。
runtime
Tokio 运行时。
signal
Tokio 的异步信号处理。
stream
由于 Stream trait 进入 std 的时间晚于 Tokio 1.0 发布, Tokio 大部分流相关工具已移至 tokio-stream crate。
sync
用于异步上下文的同步原语。
task
异步绿线程。
time
跟踪时间的工具。

§

join
等待多个并发分支,所有分支完成后返回。
pin
在栈上钉住一个值。
select
等待多个并发分支,首个分支完成后返回, 并取消其余分支。
task_local
声明一个 tokio::task::LocalKey 类型的新任务局部键。
try_join
等待多个并发分支,所有分支以 Ok(_) 完成 或首个 Err(_) 出现时返回。

Attribute Macros§

main
将 async 函数标记为由所选运行时执行。该宏 帮助设置 Runtime,无需用户直接使用 RuntimeBuilder
test
将 async 函数标记为由运行时执行,适合测试环境使用。 该宏帮助设置 Runtime,无需用户直接使用 RuntimeBuilder