Tokio 完全指南
Tokio 是 Rust 最流行的异步运行时(async runtime),为构建高性能、可靠的网络应用提供基础设施。
目录
核心概念
Tokio 是什么?
Tokio 是一个异步运行时,提供:
- 任务调度器 - 执行异步任务
- I/O 事件循环 - 处理网络/文件 I/O
- 定时器 - 延迟和超时
- 同步原语 - Mutex、RwLock、Semaphore 等
- 通道 - 任务间通信
为什么需要 Tokio?
// ❌ 没有 Tokio:无法运行异步代码
async fn hello() {
println!("Hello");
}
fn main() {
hello(); // 这只是创建 Future,不会执行
}
// ✅ 使用 Tokio:执行异步代码
#[tokio::main]
async fn main() {
hello().await; // 实际执行
}
Tokio vs 其他运行时
| 运行时 | 特点 | 适用场景 |
|---|---|---|
| tokio | 功能完整、高性能、多线程 | 网络服务、通用应用 |
| async-std | 类似标准库 API | 简单应用 |
| smol | 轻量级 | 嵌入式、小型应用 |
入门使用
安装
[dependencies]
tokio = { version = "1", features = ["full"] }
常用 Features
[dependencies]
tokio = { version = "1", features = [
"rt-multi-thread", # 多线程运行时
"macros", # #[tokio::main] 等宏
"net", # TCP/UDP 网络
"io-util", # AsyncReadExt 等工具
"time", # 定时器
"sync", # 同步原语
"fs", # 异步文件 I/O
"process", # 异步进程
"signal", # 信号处理
] }
# 或简单使用所有功能
tokio = { version = "1", features = ["full"] }
Hello World
use tokio::time::{sleep, Duration};
#[tokio::main]
async fn main() {
println!("Hello");
sleep(Duration::from_secs(1)).await;
println!("World");
}
异步运行时
#[tokio::main] 宏
// 方式1:使用宏(推荐)
#[tokio::main]
async fn main() {
println!("Hello Tokio");
}
// 宏展开后相当于:
fn main() {
tokio::runtime::Builder::new_multi_thread()
.enable_all()
.build()
.unwrap()
.block_on(async {
println!("Hello Tokio");
})
}
自定义运行时
多线程运行时
use tokio::runtime::Runtime;
fn main() {
let rt = Runtime::new().unwrap();
rt.block_on(async {
println!("Running on multi-thread runtime");
});
}
// 自定义配置
fn main() {
let rt = tokio::runtime::Builder::new_multi_thread()
.worker_threads(4) // 4 个工作线程
.thread_name("my-pool") // 线程名称
.thread_stack_size(3 * 1024 * 1024) // 栈大小
.enable_all() // 启用所有功能
.build()
.unwrap();
rt.block_on(async {
println!("Custom runtime");
});
}
单线程运行时
fn main() {
let rt = tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()
.unwrap();
rt.block_on(async {
println!("Running on single-thread runtime");
});
}
Runtime Handle
use tokio::runtime::Handle;
#[tokio::main]
async fn main() {
// 获取当前运行时句柄
let handle = Handle::current();
// 在另一个线程中使用运行时
std::thread::spawn(move || {
handle.block_on(async {
println!("Running async code in sync thread");
});
});
}
spawn_blocking - 运行阻塞代码
use tokio::task;
#[tokio::main]
async fn main() {
// CPU 密集型任务
let result = task::spawn_blocking(|| {
// 这会在单独的线程池中运行
expensive_computation()
})
.await
.unwrap();
println!("Result: {}", result);
}
fn expensive_computation() -> u64 {
(0..1_000_000).sum()
}
任务管理
tokio::spawn - 创建新任务
use tokio::task;
#[tokio::main]
async fn main() {
// 启动新任务(不等待)
let handle = tokio::spawn(async {
println!("Task 1");
42
});
// 继续执行其他工作
println!("Main task");
// 等待任务完成
let result = handle.await.unwrap();
println!("Task result: {}", result);
}
并发执行多个任务
#[tokio::main]
async fn main() {
let task1 = tokio::spawn(async {
tokio::time::sleep(tokio::time::Duration::from_secs(1)).await;
println!("Task 1 done");
1
});
let task2 = tokio::spawn(async {
tokio::time::sleep(tokio::time::Duration::from_secs(2)).await;
println!("Task 2 done");
2
});
let task3 = tokio::spawn(async {
tokio::time::sleep(tokio::time::Duration::from_secs(1)).await;
println!("Task 3 done");
3
});
// 等待所有任务完成
let (r1, r2, r3) = tokio::join!(task1, task2, task3);
println!("Results: {:?}, {:?}, {:?}", r1, r2, r3);
}
JoinSet - 动态任务集合
use tokio::task::JoinSet;
#[tokio::main]
async fn main() {
let mut set = JoinSet::new();
// 动态添加任务
for i in 0..10 {
set.spawn(async move {
tokio::time::sleep(tokio::time::Duration::from_millis(100)).await;
i * 2
});
}
// 收集所有结果
while let Some(res) = set.join_next().await {
match res {
Ok(value) => println!("Task completed: {}", value),
Err(e) => eprintln!("Task failed: {}", e),
}
}
}
任务取消
use tokio::time::{sleep, Duration};
#[tokio::main]
async fn main() {
let handle = tokio::spawn(async {
loop {
println!("Working...");
sleep(Duration::from_secs(1)).await;
}
});
// 运行 3 秒后取消
sleep(Duration::from_secs(3)).await;
handle.abort();
// 检查是否被取消
match handle.await {
Ok(_) => println!("Task completed"),
Err(e) if e.is_cancelled() => println!("Task was cancelled"),
Err(e) => println!("Task failed: {}", e),
}
}
LocalSet - 非 Send 任务
use tokio::task::LocalSet;
use std::rc::Rc;
#[tokio::main]
async fn main() {
let local = LocalSet::new();
// Rc 不是 Send,不能用普通 spawn
let data = Rc::new(42);
local.spawn_local(async move {
println!("Data: {}", data);
});
local.await;
}
异步 I/O
TCP 服务器
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?;
println!("服务器启动于 127.0.0.1:8080");
loop {
let (mut socket, addr) = listener.accept().await?;
println!("新连接: {}", addr);
// 为每个连接创建新任务
tokio::spawn(async move {
let mut buf = vec![0; 1024];
loop {
match socket.read(&mut buf).await {
Ok(0) => return, // 连接关闭
Ok(n) => {
// 回显数据
if socket.write_all(&buf[0..n]).await.is_err() {
return;
}
}
Err(_) => return,
}
}
});
}
}
TCP 客户端
use tokio::net::TcpStream;
use tokio::io::{AsyncReadExt, AsyncWriteExt};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut stream = TcpStream::connect("127.0.0.1:8080").await?;
println!("已连接到服务器");
// 发送数据
stream.write_all(b"Hello, Server!").await?;
// 读取响应
let mut buf = vec![0; 1024];
let n = stream.read(&mut buf).await?;
println!("收到响应: {}", String::from_utf8_lossy(&buf[0..n]));
Ok(())
}
UDP
use tokio::net::UdpSocket;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let socket = UdpSocket::bind("127.0.0.1:8080").await?;
let mut buf = [0; 1024];
loop {
let (len, addr) = socket.recv_from(&mut buf).await?;
println!("收到 {} 字节,来自 {}", len, addr);
// 回显
socket.send_to(&buf[0..len], addr).await?;
}
}
异步文件操作
use tokio::fs::{File, OpenOptions};
use tokio::io::{AsyncReadExt, AsyncWriteExt};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// 写文件
let mut file = File::create("hello.txt").await?;
file.write_all(b"Hello, Tokio!").await?;
// 读文件
let mut file = File::open("hello.txt").await?;
let mut contents = String::new();
file.read_to_string(&mut contents).await?;
println!("文件内容: {}", contents);
// 追加写入
let mut file = OpenOptions::new()
.append(true)
.open("hello.txt")
.await?;
file.write_all(b"\nNew line").await?;
// 读取整个文件
let contents = tokio::fs::read_to_string("hello.txt").await?;
println!("{}", contents);
Ok(())
}
异步进程
use tokio::process::Command;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let output = Command::new("echo")
.arg("Hello from Tokio")
.output()
.await?;
println!("Status: {}", output.status);
println!("Stdout: {}", String::from_utf8_lossy(&output.stdout));
Ok(())
}
同步原语
Mutex - 互斥锁
use tokio::sync::Mutex;
use std::sync::Arc;
#[tokio::main]
async fn main() {
let counter = Arc::new(Mutex::new(0));
let mut handles = vec![];
for _ in 0..10 {
let counter = Arc::clone(&counter);
let handle = tokio::spawn(async move {
let mut num = counter.lock().await;
*num += 1;
});
handles.push(handle);
}
for handle in handles {
handle.await.unwrap();
}
println!("Result: {}", *counter.lock().await);
}
RwLock - 读写锁
use tokio::sync::RwLock;
use std::sync::Arc;
#[tokio::main]
async fn main() {
let data = Arc::new(RwLock::new(vec![1, 2, 3]));
// 多个读者
let data1 = Arc::clone(&data);
tokio::spawn(async move {
let read_guard = data1.read().await;
println!("Reader 1: {:?}", *read_guard);
});
let data2 = Arc::clone(&data);
tokio::spawn(async move {
let read_guard = data2.read().await;
println!("Reader 2: {:?}", *read_guard);
});
// 一个写者
tokio::time::sleep(tokio::time::Duration::from_millis(100)).await;
let mut write_guard = data.write().await;
write_guard.push(4);
println!("Writer: {:?}", *write_guard);
}
Semaphore - 信号量
use tokio::sync::Semaphore;
use std::sync::Arc;
#[tokio::main]
async fn main() {
// 最多 3 个并发任务
let semaphore = Arc::new(Semaphore::new(3));
let mut handles = vec![];
for i in 0..10 {
let permit = semaphore.clone().acquire_owned().await.unwrap();
let handle = tokio::spawn(async move {
println!("Task {} 开始", i);
tokio::time::sleep(tokio::time::Duration::from_secs(1)).await;
println!("Task {} 完成", i);
drop(permit); // 释放许可
});
handles.push(handle);
}
for handle in handles {
handle.await.unwrap();
}
}
Barrier - 屏障
use tokio::sync::Barrier;
use std::sync::Arc;
#[tokio::main]
async fn main() {
let barrier = Arc::new(Barrier::new(3));
let mut handles = vec![];
for i in 0..3 {
let b = Arc::clone(&barrier);
handles.push(tokio::spawn(async move {
println!("Task {} 到达屏障前", i);
b.wait().await;
println!("Task {} 通过屏障", i);
}));
}
for handle in handles {
handle.await.unwrap();
}
}
Notify - 通知
use tokio::sync::Notify;
use std::sync::Arc;
#[tokio::main]
async fn main() {
let notify = Arc::new(Notify::new());
let notify2 = notify.clone();
let handle = tokio::spawn(async move {
println!("等待通知...");
notify2.notified().await;
println!("收到通知!");
});
tokio::time::sleep(tokio::time::Duration::from_secs(1)).await;
println!("发送通知");
notify.notify_one();
handle.await.unwrap();
}
定时器
sleep - 延迟
use tokio::time::{sleep, Duration};
#[tokio::main]
async fn main() {
println!("开始");
sleep(Duration::from_secs(2)).await;
println!("2秒后");
}
interval - 定时器
use tokio::time::{interval, Duration};
#[tokio::main]
async fn main() {
let mut interval = interval(Duration::from_secs(1));
for i in 0..5 {
interval.tick().await;
println!("Tick {}", i);
}
}
timeout - 超时
use tokio::time::{timeout, Duration, sleep};
#[tokio::main]
async fn main() {
let result = timeout(Duration::from_secs(2), async {
sleep(Duration::from_secs(3)).await;
"完成"
})
.await;
match result {
Ok(value) => println!("完成: {}", value),
Err(_) => println!("超时!"),
}
}
Instant - 时间点
use tokio::time::Instant;
#[tokio::main]
async fn main() {
let start = Instant::now();
tokio::time::sleep(tokio::time::Duration::from_secs(1)).await;
let elapsed = start.elapsed();
println!("耗时: {:?}", elapsed);
}
sleep_until - 睡眠到指定时间
use tokio::time::{sleep_until, Instant, Duration};
#[tokio::main]
async fn main() {
let deadline = Instant::now() + Duration::from_secs(5);
println!("等待到 {:?}", deadline);
sleep_until(deadline).await;
println!("时间到!");
}
通道 (Channels)
mpsc - 多生产者单消费者
use tokio::sync::mpsc;
#[tokio::main]
async fn main() {
let (tx, mut rx) = mpsc::channel(32); // 缓冲区大小 32
// 发送者
tokio::spawn(async move {
for i in 0..10 {
tx.send(i).await.unwrap();
}
});
// 接收者
while let Some(value) = rx.recv().await {
println!("收到: {}", value);
}
}
多个发送者
use tokio::sync::mpsc;
#[tokio::main]
async fn main() {
let (tx, mut rx) = mpsc::channel(32);
// 多个发送者
for i in 0..3 {
let tx = tx.clone();
tokio::spawn(async move {
tx.send(format!("Message from sender {}", i)).await.unwrap();
});
}
drop(tx); // 关闭原始发送者
// 接收所有消息
while let Some(msg) = rx.recv().await {
println!("{}", msg);
}
}
unbounded_channel - 无界通道
use tokio::sync::mpsc;
#[tokio::main]
async fn main() {
let (tx, mut rx) = mpsc::unbounded_channel();
tokio::spawn(async move {
for i in 0..10 {
tx.send(i).unwrap(); // 注意:不是异步的
}
});
while let Some(value) = rx.recv().await {
println!("收到: {}", value);
}
}
oneshot - 一次性通道
use tokio::sync::oneshot;
#[tokio::main]
async fn main() {
let (tx, rx) = oneshot::channel();
tokio::spawn(async move {
tokio::time::sleep(tokio::time::Duration::from_secs(1)).await;
tx.send("完成").unwrap();
});
match rx.await {
Ok(value) => println!("收到: {}", value),
Err(_) => println!("发送者已关闭"),
}
}
broadcast - 广播通道
use tokio::sync::broadcast;
#[tokio::main]
async fn main() {
let (tx, mut rx1) = broadcast::channel(16);
let mut rx2 = tx.subscribe();
let mut rx3 = tx.subscribe();
tokio::spawn(async move {
for i in 0..5 {
tx.send(i).unwrap();
}
});
let handle1 = tokio::spawn(async move {
while let Ok(value) = rx1.recv().await {
println!("Receiver 1: {}", value);
}
});
let handle2 = tokio::spawn(async move {
while let Ok(value) = rx2.recv().await {
println!("Receiver 2: {}", value);
}
});
let handle3 = tokio::spawn(async move {
while let Ok(value) = rx3.recv().await {
println!("Receiver 3: {}", value);
}
});
handle1.await.unwrap();
handle2.await.unwrap();
handle3.await.unwrap();
}
watch - 监视通道
use tokio::sync::watch;
#[tokio::main]
async fn main() {
let (tx, mut rx) = watch::channel("初始值");
tokio::spawn(async move {
loop {
if rx.changed().await.is_ok() {
println!("值变为: {}", *rx.borrow());
} else {
break;
}
}
});
tokio::time::sleep(tokio::time::Duration::from_secs(1)).await;
tx.send("新值1").unwrap();
tokio::time::sleep(tokio::time::Duration::from_secs(1)).await;
tx.send("新值2").unwrap();
tokio::time::sleep(tokio::time::Duration::from_secs(1)).await;
}
流 (Streams)
Stream Trait
use tokio_stream::{self as stream, StreamExt};
#[tokio::main]
async fn main() {
let mut stream = stream::iter(vec![1, 2, 3, 4, 5]);
while let Some(value) = stream.next().await {
println!("值: {}", value);
}
}
创建流
use tokio_stream::{StreamExt, wrappers::IntervalStream};
use tokio::time::{interval, Duration};
#[tokio::main]
async fn main() {
// 从定时器创建流
let interval = interval(Duration::from_secs(1));
let mut stream = IntervalStream::new(interval);
for _ in 0..5 {
stream.next().await;
println!("Tick");
}
}
流转换
use tokio_stream::{self as stream, StreamExt};
#[tokio::main]
async fn main() {
let stream = stream::iter(vec![1, 2, 3, 4, 5]);
// map
let doubled = stream.map(|x| x * 2);
// filter
let evens = doubled.filter(|x| x % 2 == 0);
// take
let mut first_three = evens.take(3);
while let Some(value) = first_three.next().await {
println!("值: {}", value);
}
}
流合并
use tokio_stream::{self as stream, StreamExt};
#[tokio::main]
async fn main() {
let stream1 = stream::iter(vec![1, 2, 3]);
let stream2 = stream::iter(vec![4, 5, 6]);
// 合并两个流
let mut merged = stream::iter(vec![stream1, stream2]).flatten();
while let Some(value) = merged.next().await {
println!("值: {}", value);
}
}
实用工具
select! - 选择第一个完成的
use tokio::time::{sleep, Duration};
#[tokio::main]
async fn main() {
let mut count = 0;
loop {
tokio::select! {
_ = sleep(Duration::from_secs(1)) => {
count += 1;
println!("计数: {}", count);
}
_ = sleep(Duration::from_secs(5)), if count >= 3 => {
println!("5秒过去了");
break;
}
}
}
}
join! - 等待所有完成
use tokio::time::{sleep, Duration};
#[tokio::main]
async fn main() {
let task1 = async {
sleep(Duration::from_secs(1)).await;
"Task 1"
};
let task2 = async {
sleep(Duration::from_secs(2)).await;
"Task 2"
};
let task3 = async {
sleep(Duration::from_secs(1)).await;
"Task 3"
};
let (r1, r2, r3) = tokio::join!(task1, task2, task3);
println!("结果: {}, {}, {}", r1, r2, r3);
}
try_join! - 遇错即停
use tokio::time::{sleep, Duration};
async fn task1() -> Result<&'static str, &'static str> {
sleep(Duration::from_secs(1)).await;
Ok("Task 1 成功")
}
async fn task2() -> Result<&'static str, &'static str> {
sleep(Duration::from_millis(500)).await;
Err("Task 2 失败")
}
async fn task3() -> Result<&'static str, &'static str> {
sleep(Duration::from_secs(2)).await;
Ok("Task 3 成功")
}
#[tokio::main]
async fn main() {
match tokio::try_join!(task1(), task2(), task3()) {
Ok((r1, r2, r3)) => println!("{}, {}, {}", r1, r2, r3),
Err(e) => println!("错误: {}", e),
}
}
pin! - 固定在栈上
use tokio::time::{sleep, Duration};
use tokio::pin;
#[tokio::main]
async fn main() {
let task = async {
sleep(Duration::from_secs(1)).await;
"完成"
};
pin!(task);
let result = task.await;
println!("结果: {}", result);
}
性能优化
1. 选择合适的运行时
// 多线程运行时(默认)- 适合 CPU 密集和 I/O 混合
#[tokio::main]
async fn main() { }
// 单线程运行时 - 适合纯 I/O
#[tokio::main(flavor = "current_thread")]
async fn main() { }
2. 调整工作线程数
fn main() {
tokio::runtime::Builder::new_multi_thread()
.worker_threads(num_cpus::get()) // 根据 CPU 核心数
.build()
.unwrap()
.block_on(async {
// ...
});
}
3. 使用 spawn_blocking 处理阻塞操作
#[tokio::main]
async fn main() {
// ❌ 错误:阻塞运行时
let data = std::fs::read("large_file.txt").unwrap();
// ✅ 正确:在阻塞线程池执行
let data = tokio::task::spawn_blocking(|| {
std::fs::read("large_file.txt").unwrap()
})
.await
.unwrap();
}
4. 缓冲和批处理
use tokio::sync::mpsc;
#[tokio::main]
async fn main() {
let (tx, mut rx) = mpsc::channel(1000); // 大缓冲区
// 批量处理
let mut batch = Vec::new();
while let Some(item) = rx.recv().await {
batch.push(item);
if batch.len() >= 100 {
process_batch(&batch).await;
batch.clear();
}
}
}
async fn process_batch(batch: &[i32]) {
// 批量处理
}
5. 避免过度 spawn
// ❌ 不好:为每个小任务 spawn
for i in 0..1000 {
tokio::spawn(async move {
small_work(i).await;
});
}
// ✅ 更好:批量处理
const CHUNK_SIZE: usize = 100;
for chunk in (0..1000).collect::<Vec<_>>().chunks(CHUNK_SIZE) {
tokio::spawn(async move {
for i in chunk {
small_work(*i).await;
}
});
}
6. 使用 Semaphore 限制并发
use tokio::sync::Semaphore;
use std::sync::Arc;
#[tokio::main]
async fn main() {
let semaphore = Arc::new(Semaphore::new(10)); // 最多 10 个并发
let mut handles = vec![];
for i in 0..1000 {
let permit = semaphore.clone().acquire_owned().await.unwrap();
handles.push(tokio::spawn(async move {
work(i).await;
drop(permit);
}));
}
for handle in handles {
handle.await.unwrap();
}
}
async fn work(i: usize) { }
最佳实践
1. 避免阻塞操作
// ❌ 错误
#[tokio::main]
async fn main() {
std::thread::sleep(std::time::Duration::from_secs(1)); // 阻塞!
}
// ✅ 正确
#[tokio::main]
async fn main() {
tokio::time::sleep(tokio::time::Duration::from_secs(1)).await;
}
2. 正确使用 Arc
use std::sync::Arc;
use tokio::sync::Mutex;
#[tokio::main]
async fn main() {
let data = Arc::new(Mutex::new(vec![1, 2, 3]));
let data1 = Arc::clone(&data);
tokio::spawn(async move {
let mut guard = data1.lock().await;
guard.push(4);
});
}
3. 及时释放锁
use tokio::sync::Mutex;
#[tokio::main]
async fn main() {
let data = Mutex::new(vec![1, 2, 3]);
// ✅ 好:快速释放锁
{
let mut guard = data.lock().await;
guard.push(4);
} // guard 在这里被释放
expensive_operation().await;
// ❌ 不好:持有锁过久
let mut guard = data.lock().await;
guard.push(4);
expensive_operation().await; // 仍持有锁!
}
async fn expensive_operation() { }
4. 使用 tokio::select! 处理取消
use tokio::sync::oneshot;
#[tokio::main]
async fn main() {
let (tx, rx) = oneshot::channel();
let handle = tokio::spawn(async move {
tokio::select! {
_ = long_running_task() => {
println!("任务完成");
}
_ = rx => {
println!("任务被取消");
}
}
});
tokio::time::sleep(tokio::time::Duration::from_secs(1)).await;
let _ = tx.send(()); // 取消任务
handle.await.unwrap();
}
async fn long_running_task() {
tokio::time::sleep(tokio::time::Duration::from_secs(10)).await;
}
5. 错误处理
use anyhow::Result;
#[tokio::main]
async fn main() -> Result<()> {
let result = tokio::spawn(async {
do_something().await
})
.await??; // 第一个 ? 处理 JoinError,第二个处理业务错误
Ok(())
}
async fn do_something() -> Result<()> {
Ok(())
}
本项目示例
主函数
// src/main.rs
use axum::{Router, Server};
use std::net::SocketAddr;
#[tokio::main] // Tokio 运行时
async fn main() -> anyhow::Result<()> {
// 初始化日志
tracing_subscriber::fmt()
.with_target(false)
.compact()
.init();
// 加载配置
let config = Config::from_env()?;
// 创建数据库连接池(异步)
let pool = database::create_pool(&config.database_url).await?;
// 初始化数据库(异步)
database::init_database(&pool).await?;
// 创建 Redis 客户端(异步)
let cache = RedisCache::new(&config.redis_url).await?;
// 创建应用状态
let state = Arc::new(AppState { pool, cache });
// 创建路由
let app = create_routes(state);
// 启动服务器(异步,会一直运行)
let addr: SocketAddr = format!("{}:{}", config.host, config.port).parse()?;
tracing::info!("服务器启动于 {}", addr);
Server::bind(&addr)
.serve(app.into_make_service())
.await?;
Ok(())
}
数据库连接池
// src/config/database.rs
use sqlx::MySqlPool;
pub async fn create_pool(database_url: &str) -> Result<MySqlPool, sqlx::Error> {
// Tokio 运行异步数据库连接
MySqlPool::connect(database_url).await
}
pub async fn init_database(pool: &MySqlPool) -> Result<(), sqlx::Error> {
// 异步执行 SQL
sqlx::query(
"CREATE TABLE IF NOT EXISTS users (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(255) NOT NULL UNIQUE,
email VARCHAR(255) NOT NULL UNIQUE,
password_hash VARCHAR(255) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
)"
)
.execute(pool)
.await?;
Ok(())
}
服务层
// src/services/user_service.rs
use sqlx::MySqlPool;
pub async fn get_user_by_id(
pool: &MySqlPool,
id: i64,
) -> Result<Option<User>, sqlx::Error> {
// Tokio 运行异步查询
let user = sqlx::query_as::<_, User>(
"SELECT id, username, email, password_hash, created_at, updated_at
FROM users WHERE id = ?"
)
.bind(id)
.fetch_optional(pool)
.await?;
Ok(user)
}
Redis 缓存
// src/utils/cache.rs
use redis::AsyncCommands;
pub struct RedisCache {
client: redis::Client,
}
impl RedisCache {
pub async fn new(redis_url: &str) -> Result<Self, redis::RedisError> {
let client = redis::Client::open(redis_url)?;
// 测试连接(异步)
let mut conn = client.get_async_connection().await?;
redis::cmd("PING").query_async(&mut conn).await?;
Ok(Self { client })
}
pub async fn get<T>(&self, key: &str) -> Result<Option<T>, redis::RedisError>
where
T: serde::de::DeserializeOwned,
{
// Tokio 运行异步 Redis 操作
let mut conn = self.client.get_async_connection().await?;
let value: Option<String> = conn.get(key).await?;
Ok(value.and_then(|json| serde_json::from_str(&json).ok()))
}
pub async fn set<T>(
&self,
key: &str,
value: &T,
ttl: usize,
) -> Result<(), redis::RedisError>
where
T: serde::Serialize,
{
let json = serde_json::to_string(value).unwrap();
let mut conn = self.client.get_async_connection().await?;
conn.set_ex(key, json, ttl).await
}
}
并发查询示例
// 并发查询多个用户
pub async fn get_users_concurrently(
pool: &MySqlPool,
ids: Vec<i64>,
) -> Vec<Option<User>> {
let mut handles = vec![];
for id in ids {
let pool = pool.clone();
let handle = tokio::spawn(async move {
get_user_by_id(&pool, id).await.ok().flatten()
});
handles.push(handle);
}
let mut results = vec![];
for handle in handles {
results.push(handle.await.unwrap());
}
results
}
常见问题
1. 如何在同步代码中调用异步函数?
// 方式1:使用 block_on
use tokio::runtime::Runtime;
fn sync_function() {
let rt = Runtime::new().unwrap();
let result = rt.block_on(async_function());
}
// 方式2:使用 Handle
use tokio::runtime::Handle;
fn sync_function() {
let handle = Handle::current();
let result = handle.block_on(async_function());
}
async fn async_function() -> i32 {
42
}
2. spawn 要求 'static 生命周期怎么办?
// ❌ 错误:引用不是 'static
async fn bad_example(data: &Vec<i32>) {
tokio::spawn(async {
println!("{:?}", data); // 错误!
});
}
// ✅ 方案1:使用 Arc
use std::sync::Arc;
async fn good_example(data: Arc<Vec<i32>>) {
tokio::spawn(async move {
println!("{:?}", data);
});
}
// ✅ 方案2:克隆数据
async fn clone_example(data: Vec<i32>) {
let data = data.clone();
tokio::spawn(async move {
println!("{:?}", data);
});
}
3. 如何优雅关闭?
use tokio::signal;
#[tokio::main]
async fn main() {
let (tx, mut rx) = tokio::sync::mpsc::channel(1);
// 监听关闭信号
tokio::spawn(async move {
signal::ctrl_c().await.unwrap();
println!("收到关闭信号");
tx.send(()).await.unwrap();
});
// 主任务
tokio::select! {
_ = long_running_task() => {
println!("任务完成");
}
_ = rx.recv() => {
println!("优雅关闭中...");
}
}
}
async fn long_running_task() {
loop {
tokio::time::sleep(tokio::time::Duration::from_secs(1)).await;
}
}
总结
Tokio 核心组件
- 运行时 - 执行异步任务
- 任务 - spawn、JoinSet、spawn_blocking
- I/O - TCP、UDP、文件、进程
- 同步 - Mutex、RwLock、Semaphore、Barrier
- 定时器 - sleep、interval、timeout
- 通道 - mpsc、oneshot、broadcast、watch
- 工具 - select!、join!、try_join!
何时使用 Tokio
✅ 适合:
- 网络服务(HTTP、gRPC、WebSocket)
- 数据库访问
- 微服务
- 高并发 I/O
❌ 不适合:
- CPU 密集计算(使用 rayon)
- 简单脚本
性能提示
- 选择合适的运行时(多线程 vs 单线程)
- 使用
spawn_blocking处理阻塞操作 - 合理使用缓冲和批处理
- 使用 Semaphore 限制并发
- 避免持锁跨 await 点
- 及时释放资源
Tokio 是 Rust 异步生态的基石,掌握它对构建高性能应用至关重要!