展开描述
一个用于写作可靠的网络应用程序的运行时,不以性能为价。
Tokio 是一个事件驱动的非阻塞 I/O 平台,用于使用 Rust 编程语言编写异步应用程序。 在高层次上,它提供几个主要组件:
- Tools for working with asynchronous tasks, including synchronization primitives and channels and timeouts, sleeps, and intervals.
- APIs for performing asynchronous I/O, including TCP and UDP sockets, filesystem operations, and process and signal management.
- A runtime for executing asynchronous code, including a task scheduler,
an I/O driver backed by the operating system’s event queue (
epoll,kqueue,IOCP, etc…), and a high performance timer.
入门级文档请参阅 官网。
§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 中的异步程序基于轻量级、非阻塞的
执行单元,称为 tasks。tokio::task 模块提供了
使用任务的重要工具:
- The
spawnfunction andJoinHandletype, 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, andbroadcast), for sending values between tasks, - a non-blocking
Mutex, for controlling access to a shared, mutable value, - an asynchronous
Barriertype, 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 原语,
包括 AsyncRead、 AsyncWrite 和 AsyncBufRead 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 tostd::fsbut 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 excepttest-utiland unstable features.rt: Enablestokio::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 basedExttraits.io-std: EnableStdout,StdinandStderrtypes.net: Enablestokio::nettypes such asTcpStream,UnixStreamandUdpSocket, as well as (on Unix-like systems)AsyncFdand (on FreeBSD)PollAio.time: Enablestokio::timetypes and allows the schedulers to enable the built-in timer.process: Enablestokio::processtypes.macros: Enables#[tokio::main]and#[tokio::test]macros.sync: Enables alltokio::synctypes.signal: Enables alltokio::signaltypes.fs: Enablestokio::fstypes.test-util: Enables testing based infrastructure for the Tokio 运行时。parking_lot: As a potential optimization, use theparking_lotcrate’s synchronization primitives internally. Also, this dependency is necessary to construct some of our primitives in aconstcontext.MSRVmay increase according to theparking_lotrelease in use.
注意:AsyncRead 和 AsyncWrite trait 不需要任何特性,就可以使用。
§不稳定特性
有些特性标志只在指定 tokio_unstable 标志时才可用:
tracing: Enables tracing events.io-uring: Enablesio-uring(Linux only).taskdump: Enablestaskdump(Linux only).
同样,这个标志开启了不稳定 API 的访问权限。
这个标志启用 不稳定 特性。这些特性的公开 API
可能会在 1.x 发布中舍弃。为了启用这些特性,编译时必须将 --cfg tokio_unstable 参数传递给 rustc。
这种显式的抑入使得这些特性是明确的选择性开启,
因为 Cargo 尚未直接支持此类选择性开启。
可以在项目的 .cargo/config.toml 文件中指定:
[build]
rustflags = ["--cfg", "tokio_unstable"][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 标志的情况下,支持以下特性:
syncmacrosio-utilrttime
启用任何其他特性(包括 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
- 由于
Streamtrait 进入std的时间晚于 Tokio 1.0 发布, Tokio 大部分流相关工具已移至tokio-streamcrate。 - sync
- 用于异步上下文的同步原语。
- task
- 异步绿线程。
- time
- 跟踪时间的工具。
宏§
- join
- 等待多个并发分支,所有分支完成后返回。
- pin
- 在栈上钉住一个值。
- select
- 等待多个并发分支,首个分支完成后返回, 并取消其余分支。
- task_
local - 声明一个
tokio::task::LocalKey类型的新任务局部键。 - try_
join - 等待多个并发分支,所有分支以
Ok(_)完成 或首个Err(_)出现时返回。