首页
看点啥
插画图片
首页 科技看点 Rust异步编程实践指南实用指南

Rust异步编程实践指南实用指南

2026-10-14 0

平时做技术实践时,很多问题不是概念不会,而是细节没串起来。拿“Rust异步编程实践指南”来说,它看着像小点,放到项目里常会牵出环境、配置、兼容性和维护成本。下面按实际采用顺序,把思路、关键写法和容易踩坑的地方讲清楚,便于大家直接对照操作。

实际处理时,Rust异步编程主要靠async/await 语法 和 异步运行时 来写非阻塞代码,核心是把任务表示成 Future,再由运行时(如 Tokio)去驱动执行,它适合高同时发 I/O 场景,比如网络服务、文件读写、消息处理等。

#[tokio::main]
async fn main() -> Result<()> {
    // Open a connection to the mini-redis address.
    let mut client = client::connect("127.0.0.1:6379").await?;
    // Set the key "hello" with value "world"
    client.set("hello", "world".into()).await?;
    // Get key "hello"
    let result = client.get("hello").await?;
    println!("got value from the server; result={:?}", result);
    Ok(())
}

这段代码是 Tokio 官方教程 mini-redis 的客户端示例,演示了用 async/await 连接 Redis 服务、设置和读取键值对。

逐行解析

#[tokio::main]
async fn main() -> Result<()> {

#[tokio::main]:这是属性宏,把 async fn main 转换成 Tokio 运行时的入口。展开后相当于:

fn main() {
    tokio::runtime::Runtime::new().unwrap().block_on(async {
        // 你的 async main 代码
    });
}

结合项目来看,它负责新建 Tokio 运行时、启动执行器、阻塞等待 main Future 完成。

-> Result<()>:main 得到 Result,这样能够用 ? 传播错误。这里的 Result 通常是 anyhow::Result 或 std::io::Result。如果得到 Err,程序会以非零状态码退出同时打印错误。

let mut client = client::connect("127.0.0.1:6379").await?;
  • client::connect(...):异步连接 Redis 服务器。.await 表示挂起当前任务,直到连接建立完成。
  • ?:如果连接失败,直接得到 Err,不会继续执行。
  • mut:因为后面要调用 client.set(...) 和 client.get(...),这些方法需 &mut self。
client.set("hello", "world".into()).await?;
  • set:发送 SET hello world 命令。
  • "world".into():转换成 Bytes 类型(mini-redis 用的字节缓冲区)。
  • .await?:等待命令执行完成,失败则传播错误。
let result = client.get("hello").await?;
println!("got value from the server; result={:?}", result);
  • get:发送 GET hello 命令,得到 Option。
  • {:?}:用 Debug 格式打印,因为 Bytes 不一定实现了 Display。
  • 若 key 存在,result 是 Some(Bytes);否则是 None。

背后的运行时机制

这段代码能跑起来,靠的是 Tokio 运行时在背后做这些事:

  1. #[tokio::main] 新建运行时,把 main 作为第一个 Future 交给执行器。
  2. client::connect(...).await 发起 TCP 连接。连接没建立时得到 Pending,执行器去跑其他任务。连接建立后,epoll 事件唤醒任务,继续执行。
  3. client.set(...).await 发送请求同时等待响应。等待期间任务挂起,不阻塞线程。
  4. client.get(...).await 同理。

从实现思路看,整个过程中,当前线程没有被阻塞。如果同时有多个客户端任务,它们会在同一个线程上协作式交替执行。

对比:同步版本长什么样

若用同步阻塞的方式写,代码会是这样:

fn main() -> Result<()> {
    let mut client = std::net::TcpStream::connect("127.0.0.1:6379")?;
    client.write_all(b"SET hello world\r\n")?;
    let mut buf = [0u8; 1024];
    let n = client.read(&mut buf)?;
    println!("got value: {:?}", &buf[..n]);
    Ok(())
}

区别在于:同步版本在 connect、write、read 时线程被挂起,什么都干不了。异步版本在等待时让出 CPU,执行器能够跑其他任务。

一句话总结

这段代码用 #[tokio::main] 启动 Tokio 运行时,借助 .await 异步地连接 Redis、设置和读取键值。每个 .await 点都是任务让出 CPU 的时机,等待期间线程不阻塞,执行器能够调度其他任务。这就是异步非阻塞的典型写法。

落到代码里,总的来说,rust异步编程适合结合实际项目边做边理解。先抓住核心思路,再逐步补上细节和边界处理,最后效果会更稳定,也更容易复用。

喜欢(0)

上一篇

一文完整指南Codex提示Reconnecting waiting for network的原因与解决做法

一文完整指南Codex提示Reconnecting waiting for network的原因与解决做法

下一篇

MariaDB(数据库管理系统) v13.0.2 64位 官方绿色解压版(附使用教程)实用指南

猜你喜欢