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()
相关推荐
程序员爱钓鱼35 分钟前
Rust const泛型详解:让常量也成为泛型参数
后端·面试·rust
k4m7v2pz2 小时前
ESP32-S3 + I2S 麦克风实时音频流静音问题排查:从网络到AGC的谬误溯源
rust·音频·esp32·agc·实时监听·静音排查
SomeB1oody2 小时前
【RustyML入门】7.4. 按需裁剪与模块化集成
开发语言·后端·机器学习·rust·教程
Source.Liu2 小时前
【A11】基于 PDF 渲染引擎的统一文档界面架构设计
rust·pdf
SomeB1oody6 小时前
【RustyML入门】7.3. 性能调优与并行
开发语言·后端·机器学习·rust·教程
苏灿烤鱼6 小时前
连庄+2,729,空降榜眼只+440
rust·openai·agent
CoLiuRs20 小时前
我用 Rust 写了一个 SSH 本地端口转发管理器:Via 的实现与取舍
开发语言·rust·ssh
小灰灰搞电子21 小时前
Rust+Slint 实现水波纹进度条源码分享
开发语言·rust
mounter6251 天前
GCCRS 突破与 Rust 入核:Linux 工具链的重大变革
linux·开发语言·rust·linux kernel·kernel
SomeB1oody1 天前
【RustyML入门】7.2. 深入模型持久化
开发语言·后端·机器学习·rust·教程