Rust - 用异步替代线程实现并发

关键概念对比

功能 多线程方式 异步方式
创建并发单元 thread::spawn() trpl::spawn_task()
延时等待 thread::sleep() (阻塞线程) trpl::sleep().await (非阻塞)
等待结束 join() (阻塞线程) .await (让出控制权)
并发单位 操作系统线程 (重量级) Future (轻量级状态机)

三种异步模式详解

1️⃣ 基础任务生成(示例17-6)

rust 复制代码
# extern crate trpl; // required for mdbook test 
# use std::time::Duration; 
fn main() { 
    trpl::run(async { 
        trpl::spawn_task(async { 
            for i in 1..10 { 
                println!("hi number {i} from the first task!"); 
                trpl::sleep(Duration::from_millis(500)).await; 
            } 
        }); 
        
        for i in 1..5 { 
            println!("hi number {i} from the second task!"); 
            trpl::sleep(Duration::from_millis(500)).await; 
        } 
   }); 
}

特点:

  • 主任务结束时自动终止子任务
  • 类似守护线程(daemon thread)
  • 输出顺序随机(取决于运行时调度)

2️⃣ 使用任务句柄等待

rust 复制代码
# extern crate trpl; // required for mdbook test 
# 
# use std::time::Duration; 
# 
# fn main() { 
#    trpl::run(async { 
        let handle = trpl::spawn_task(async { 
            for i in 1..10 { 
                println!("hi number {i} from the first task!");
                trpl::sleep(Duration::from_millis(500)).await; 
            } 
        }); 
        
        for i in 1..5 { 
            println!("hi number {i} from the second task!");
            trpl::sleep(Duration::from_millis(500)).await; 
        } 
        handle.await.unwrap(); 
#    }); 
#}

核心改进:

  • 通过 handle.await 确保子任务完整执行
  • 类似线程的 join(),但非阻塞
  • 输出顺序依然随机

3️⃣ 使用join组合Future(示例17-8)

rust 复制代码
# extern crate trpl; // required for mdbook test 
# 
# use std::time::Duration; 
# 
# fn main() { 
#     trpl::run(async { 
           let fut1 = async { 
               for i in 1..10 { 
                   println!("hi number {i} from the first task!"); 
                   trpl::sleep(Duration::from_millis(500)).await; 
               } 
           }; 
           
           let fut2 = async { 
               for i in 1..5 { 
                   println!("hi number {i} from the second task!"); 
                   trpl::sleep(Duration::from_millis(500)).await; 
               } 
           };
           trpl::join(fut1, fut2).await; 
#     }); 
#}

革命性变化:

  • 不需要生成任务,直接操作 Future 对象
  • 运行时公平轮询(round-robin)
  • 输出顺序固定(交替执行)
text 复制代码
hi number 1 from the first task!  // fut1
hi number 1 from the second task! // fut2
hi number 2 from the first task!  // fut1
...

为什么顺序固定?关键机制

  1. 公平调度器 :

    • trpl::join 内部以固定频率轮询每个 Future
    • 每次只推进少量执行(到下一个 .await 点)
  2. 协作式让步 :

    rust 复制代码
    // 每次遇到 .await 都会让出控制权
    trpl::sleep(...).await; // ↑ 让出点
  3. 执行流程 :

    • 轮询 fut1 → 执行到第一个 sleep().await → 暂停
    • 轮询 fut2 → 执行到第一个 sleep().await → 暂停
    • 重复直到两者完成

与线程的本质区别

特性 线程模型 异步模型
内存开销 MB级(线程栈) KB级(状态机)
切换代价 高(内核切换) 极低(用户态切换)
调度单位 整个线程 单个 .await 分段
控制粒度 粗(操作系统控制) 细(程序员可控)

实践建议

  1. 何时用异步:

    • I/O密集型任务(网络请求/文件操作)
    • 高并发服务(如Web服务器)
    • 需要数千以上"并发单元"的场景
  2. 何时用线程:

    • CPU密集型计算
    • 阻塞型操作(如复杂计算)
    • 需要利用多核并行(非并发)
  3. 混合使用:

    rust 复制代码
    // CPU密集型任务放在专用线程
    tokio::task::spawn_blocking(|| heavy_computation());

真实世界映射

示例中的伪API 实际生产级对应
trpl::run #[tokio::main]
trpl::sleep tokio::time::sleep()
trpl::join tokio::join!宏
spawn_task tokio::spawn()
相关推荐
wflynn6 小时前
GitHub 今日推荐|wordcraft:用 Rust 重写 Word 内核并开放给 AI 调用
rust·开源·github
I'm Jie6 小时前
【开源】7 天,我用 Rust 复刻了 FinalShell!Rhost v1.0.0 发布
开发语言·rust·开源
小灰灰搞电子7 小时前
Rust+Slint 实现一个终端软件源码分享(半成品)
开发语言·rust
恋喵大鲤鱼8 小时前
Rust str 与 String 类型的区别
rust
miofly8 小时前
GitHub 今日推荐|fsearch:Rust 打造 macOS 毫秒级全盘文件名与内容搜索工具
rust·开源·github
大鹏的NLP博客9 小时前
Rust 的本质:用数学约束实现编译期内存安全
安全·rust
Kapaseker10 小时前
Rust 读多写少还在用 Mutex?别让线程白白排队
rust
EatFan10 小时前
2026 Rust 后端技术栈选型:Axum 0.8 + Tokio + SQLx 全链路怎么搭
开发语言·后端·rust·tokio·serde·axum·sqlx
Zoom21 小时前
【开源】7 天,我用 Rust 复刻了 FinalShell!Rhost v1.0.0 发布
rust·electron·shell
wflynn1 天前
GitHub 今日推荐|ts-rust:把微软 TypeScript-Go 编译器逐行移植成 Rust 实现
rust·typescript·开源·github·compiler·tsc