Rust 学习笔记(44)-异步运行时Tokio

参考章节《Tokio官方文档Setup
参考章节《Tokio官方文档Hello Tokio
参考章节《Rust语言圣经(Rust Course)》第4.2章 Tokio 使用指南

Async Rust,最最重要的莫过于底层的异步运行时,它提供了执行器、任务调度、异步 API 等核心服务。
async/await 特性编写的异步代码要运行起来,就必须依赖于异步运行时,否则这些代码将毫无用处。

Tokio 是由 社区驱动的 Rust 中最有名的异步运行时,也是目前Rust 异步运行时事实标准
那么从这一节开始,我们将一起学习 Tokio 的常见用法,让我们开始吧

准备工作

我们将根据《Tokio官方文档》 的例子来学习

首先,我们安装 mini-redis 服务器,它用于测试我们的客户端,项目地址

1
$ cargo install mini-redis

启动服务器

1
$ mini-redis-server

然后,在一个单独的终端窗口中,尝试使用 mini-redis-cli 获取 foo

1
$ mini-redis-cli get foo

你应该看到(nil)

Hello Tokio

我们新建一个工程 my-redis,并在 Cargo.toml 中引入 tokio

1
2
tokio = { version = "1", features = ["full"] }
mini-redis = "0.4"

features = ["full"] 表示引入所有特性,Tokio 有很多功能和特性,例如 TCP,UDP,Unix sockets,同步工具,多调度类型等等
不是每个应用都需要所有的这些特性。为了优化编译时间和最终生成可执行文件大小、内存占用大小,应用可以对这些特性进行可选引入。

然后我们在 main.rs 中写入如下代码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
use mini_redis::{client, Result};

#[tokio::main]
async fn main() -> Result<()> {
    // 建立与 mini-redis 服务器的连接
    // `client::connect` 函数由 `mini-redis` 包提供,它使用异步的方式跟指定的远程 IP 地址建立 TCP 长连接,一旦连接建立成功,那 client 的赋值初始化也将完成。  
    // 特别值得注意的是:虽然该连接是异步建立的,但是从代码本身来看,完全是同步的代码编写方式,唯一能说明异步的点就是 `.await`。
    let mut client = client::connect("127.0.0.1:6379").await?;

    // 设置 key: "hello" 和 值: "world"
    client.set("hello", "world".into()).await?;

    // 获取"key=hello"的值
    let result = client.get("hello").await?;

    println!("got value from the server; result={:?}", result);
    Ok(())
}

以上代码中,我们比较陌生的是 async fn main#[tokio::main],我们来看看它们的作用

  1. .await 只能在 async 函数中使用,如果是以前的 fn main,那它内部是无法直接使用 async函数的
  2. 异步运行时本身是需要初始化的,而 #[tokio::main] 宏会将 async fn main 隐式的转换为 fn main 的同时还会对整个异步运行时进行了初始化。

例如

1
2
3
4
#[tokio::main]
async fn main() {
    println!("hello");
}

将被转换成:

1
2
3
4
5
6
fn main() {
    let mut rt = tokio::runtime::Runtime::new().unwrap();
    rt.block_on(async {
        println!("hello");
    })
}
updatedupdated2025-03-012025-03-01