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()
相关推荐
T1an-15 小时前
Axum web框架【实习】
学习·rust
中国胖子风清扬5 小时前
Rust 日志库完全指南:从入门到精通
spring boot·后端·rust·学习方法·logback
小喷友8 小时前
阶段四:实战(项目开发能力)
前端·rust
小喷友1 天前
阶段三:进阶(Rust 高级特性)
前端·rust
Python私教1 天前
源滚滚Rust全栈班v1.02 无符号整数详解
开发语言·后端·rust
专注VB编程开发20年2 天前
CSS 的命名方式像是 PowerShell 的动词-名词结构,缺乏面向对象的层级关系
开发语言·后端·rust
伍哥的传说2 天前
Tailwind CSS v4 终极指南:体验 Rust 驱动的闪电般性能与现代化 CSS 工作流
前端·css·rust·tailwindcss·tailwind css v4·lightning css·utility-first
专注VB编程开发20年2 天前
rust语言-对象多级访问
服务器·前端·rust
编码浪子2 天前
趣味学RUST基础篇(构建一个命令行程序2重构)
开发语言·重构·rust
susnm2 天前
组件生命周期
rust·全栈