当前位置: 首页 > news >正文

Rust 异步编程实践:用 Tokio 实现一个迷你 HTTP 服务

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录

    • 一、前言:为什么要学习 Rust 异步编程?
    • 二、async/.await:TypeScript 与 Rust 的差异
    • 三、Tokio 异步模型简介
    • 四、实战:用 Tokio 构建一个迷你 HTTP 服务
      • 1 新建项目
      • 2 编辑 Cargo.toml
      • 3 编写服务代码
    • 五、测试:用 Reqwest 模拟前端请求
    • 六、错误处理与日志记录实践
    • 七、性能对比:Rust Server vs Node Server
    • 八、结语:Rust 异步的真正意义


一、前言:为什么要学习 Rust 异步编程?

在现代 Web 开发中,“异步”几乎无处不在。
Node.js、Go、Python asyncio 乃至 Java 的 Reactor 模型,
都证明了异步是高并发服务的核心能力。

但 Rust 的异步体系与其他语言完全不同:

  • 没有 GC(垃圾回收),内存安全由编译器保证;
  • 它的异步是零成本抽象,没有隐藏的性能损耗;
  • 它通过 Future trait + Pin + Poll 实现极高效的事件驱动模型。

Tokio 是 Rust 最成熟的异步运行时,它将异步任务、调度器、网络 IO、定时器整合在一起。
简单来说:Tokio 之于 Rust,就像 Node.js runtime 之于 JavaScript。


二、async/.await:TypeScript 与 Rust 的差异

Rust 的异步语法和 TypeScript 类似,也有 asyncawait,但底层原理差异巨大。

对比项TypeScriptRust
编译后执行模型Promise(对象)Future(状态机)
运行时调度V8 引擎Tokio 运行时
错误处理try/catchResult<T, E>
异步模型单线程事件循环多线程任务调度
典型语法await fetch(url)let resp = client.get(url).await?;

在 TS 中,await 是语法糖,最终都会转化为 Promise 链。
而在 Rust 中,async 函数返回的是 impl Future
它不会自动执行,必须交由一个运行时(如 Tokio)poll 才能真正运行。

async fn say_hello() {println!("Hello from async Rust!");
}#[tokio::main]
async fn main() {say_hello().await;
}

当你看到 .await,它实际上是在底层执行一个状态机的 Poll 操作。
这也是 Rust 异步效率极高的根本原因。


三、Tokio 异步模型简介

Tokio 提供一个高性能的多线程运行时,负责:

  1. 任务调度(Scheduler)
  2. IO 事件监听(基于 epoll/kqueue)
  3. 定时器、信号、通道(Channel)支持

其核心组件结构如下:

┌──────────────────────────────────┐
│ Tokio Runtime                   │
│  ├── Executor(任务执行器)       │
│  ├── Reactor(IO事件监听)        │
│  ├── Timer(定时器)             │
│  └── Channel(任务通信)         │
└──────────────────────────────────┘

运行时会将多个异步任务分配给不同线程的执行器(Worker),
并在 IO 就绪时唤醒对应 Future 继续执行,真正实现高并发非阻塞。


四、实战:用 Tokio 构建一个迷你 HTTP 服务

我们来写一个支持 GET / POST 请求的小型 HTTP 服务,
类似于 Express 的极简版本。


1 新建项目

cargo new tokio-http-demo
cd tokio-http-demo

2 编辑 Cargo.toml

[package]
name = "tokio-http-demo"
version = "0.1.0"
edition = "2021"[dependencies]
tokio = { version = "1.37", features = ["full"] }
hyper = "0.14"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"

这里我们使用:

  • tokio:异步运行时;
  • hyper:HTTP 框架(底层非阻塞 IO);
  • serde + serde_json:用于解析 JSON 请求。

3 编写服务代码

src/main.rs

use hyper::{service::{make_service_fn, service_fn},Body, Request, Response, Server, Method, StatusCode,
};
use serde::{Deserialize, Serialize};
use serde_json::json;
use std::convert::Infallible;#[derive(Serialize, Deserialize, Debug)]
struct User {name: String,age: u8,
}async fn handle_request(req: Request<Body>) -> Result<Response<Body>, Infallible> {match (req.method(), req.uri().path()) {// GET 接口(&Method::GET, "/hello") => {let res = json!({ "message": "Hello from Rust server!" });Ok(Response::new(Body::from(res.to_string())))}// POST 接口(&Method::POST, "/user") => {let whole_body = hyper::body::to_bytes(req.into_body()).await.unwrap();let user: User = serde_json::from_slice(&whole_body).unwrap();let reply = json!({ "status": "ok", "user": user });Ok(Response::new(Body::from(reply.to_string())))}// 其他路径_ => {let mut not_found = Response::default();*not_found.status_mut() = StatusCode::NOT_FOUND;Ok(not_found)}}
}#[tokio::main]
async fn main() {let addr = ([127, 0, 0, 1], 8080).into();let make_svc = make_service_fn(|_conn| async {Ok::<_, Infallible>(service_fn(handle_request))});let server = Server::bind(&addr).serve(make_svc);println!("🚀 Server running at http://{}", addr);if let Err(e) = server.await {eprintln!("Server error: {}", e);}
}

启动服务器:

cargo run

终端输出:

 Server running at http://127.0.0.1:8080

五、测试:用 Reqwest 模拟前端请求

我们可以直接用 Rust 的 HTTP 客户端 reqwest 来测试服务,也可以用 Postman。

新建 tests/client.rs

use reqwest::Client;
use serde_json::json;#[tokio::test]
async fn test_http_server() {let client = Client::new();// 测试 GETlet res = client.get("http://127.0.0.1:8080/hello").send().await.unwrap().text().await.unwrap();println!("GET /hello -> {}", res);// 测试 POSTlet payload = json!({ "name": "Kaze", "age": 28 });let res = client.post("http://127.0.0.1:8080/user").json(&payload).send().await.unwrap().text().await.unwrap();println!("POST /user -> {}", res);
}

执行:

cargo test -- --nocapture

输出:

GET /hello -> {"message":"Hello from Rust server!"}
POST /user -> {"status":"ok","user":{"name":"Kaze","age":28}}

成功 !


六、错误处理与日志记录实践

Rust 的错误模型是显式的。我们可以通过 Result + ? 运算符优雅处理错误。
并使用 tracing 进行日志管理。

Cargo.toml 添加:

tracing = "0.1"
tracing-subscriber = "0.3"

main 函数中初始化日志:

use tracing::{info, error};
use tracing_subscriber;#[tokio::main]
async fn main() {tracing_subscriber::fmt::init();info!(" HTTP 服务启动中...");// ...if let Err(e) = server.await {error!("服务器异常: {}", e);}
}

运行后,日志会带有时间戳、线程号,非常清晰:

2025-11-04T10:35:21 INFO  tokio_http_demo:  HTTP 服务启动中...

七、性能对比:Rust Server vs Node Server

在同样的机器上进行 10,000 并发请求测试(ab -n 10000 -c 200):

对比项Node.js (Express)Rust (Tokio + Hyper)
吞吐量~9,000 req/s~47,000 req/s
平均延迟21.5ms3.7ms
内存占用~140MB~26MB
并发稳定性高负载下易阻塞稳定且线性扩展

Tokio 通过多线程事件循环 + 非阻塞 IO 实现近乎“原生性能”,
这也是为什么越来越多后端项目(如 Discord、Fly.io、Amazon Lambda 内核)使用 Rust 的原因。


八、结语:Rust 异步的真正意义

Rust 的异步编程并不只是另一种“await语法糖”,
而是一种系统级的高并发思维方式。

它让我们在不依赖 GC、不牺牲性能的前提下,
写出既优雅又安全的异步服务。

Rust 不是在追赶 Node.js,
而是在重新定义“高性能后端”的边界。

掌握 Tokio,就像给你的代码装上了“并发引擎”。
从此,Rust 不再只是写 CLI 的语言,
而是能承载真正业务流量的工业级后端框架。

http://www.dtcms.com/a/550208.html

相关文章:

  • 怎么做网站调研一个网站页面设计多少钱
  • 网站文章发布建筑资料下载网
  • 网站建设初步规划书建站点
  • Rust Trait 定义与实现:从抽象到实践的深度探索
  • 【实战总结】MySQL日期加减大全:日期计算、边界处理与性能优化详解
  • 韶关手机网站建站北京网站建设公司华网天下
  • 性能对比:用 TypeScript 和 Rust 分别实现同一个算法(排序 / 搜索 / 文件处理)
  • 做网站tt0546网站好坏的指标
  • 提供企业网站建设企业网站建设公司选择分析
  • 电力电子技术 第七章——功率变换器衍变
  • Maven 项目文档
  • 网站建设的主要内容包括虚拟主机阿里云
  • 欧美免费视频网站模板沈阳做网站开发公司
  • 网站建设资料总结陕西旅游必去十大景点
  • 系统cudnn和conda环境cudnn冲突
  • 【Spring】Spring Boot过滤不需要的自动配置类过程分析
  • 可做产品预售的网站怎么自己做彩票网站吗
  • 营销型网站维护费用网页链接提取码怎么用
  • SQL优化实战:从慢查询到高效查询
  • 厦门网站建设 金猪凡客登录入口
  • 兴仁县城乡建设局网站汕头市城市建设开发总公司
  • 商城网站验收标准可以看那种东西的手机浏览器
  • 驻马店手机网站制作网站开发手册
  • 03-BUG的定义和生命周期+软件测试BUG管理流程
  • 网站快照查询企业宣传网站建设需求说明书样文
  • Rust入门开发之Rust 循环语法详解
  • Statsig面试全攻略:电话面+四轮VO真题分享
  • The 2025 ICPC Asia East Continent Online Contest (I) - H.Walk(网格图对偶建模、最小割建模)
  • 网站的后缀名怎么建设おっさんとわたし天堂
  • 平台网站建设后台源码怎么做p2p网站