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()
相关推荐
怪我冷i5 小时前
Rust 智能指针 RefCell<T> 与内部可变性模式
rust
YOLOW929 小时前
两周五个版本:我用 Rust 写的 AI 数据引擎 PageSift,0.81 系列做了什么
rust
西风测评9 小时前
SSH 中文乱码的根源:locale、SendEnv 与 env 请求
rust
unconditional9 小时前
我数了下 sdkm 的源码:41 个工具的安装逻辑,四分之三是同一行
rust·开源
niyongsheng1 天前
3D 装箱算法工程化:数据结构、放置启发式与支撑规则
数据结构·算法·rust
Hello.Reader1 天前
tsrs 技术解析用 Rust 移植 TypeScript 7,类型检查还能怎样提速?
开发语言·rust·typescript
王仔小奶1 天前
Rust 正在接管金融圈?深度拆解一份高薪 FinTech 岗位 JD
开发语言·金融·rust
你为她披上外套时我正站在窗外1 天前
subtitler v2.10 发布:3 个社区 PR、一个一天修掉的 issue,和关于 uuencode 的真相
rust
Thneonl1 天前
熔断不是开关是状态机:Claude Code 路由内核的 3 条红线
人工智能·rust
Thneonl1 天前
一个 Claude Code 本地代理,凭啥配了 3 个观测出口?
人工智能·rust