Published on

Rust 异步并发实战:从逻辑拆机到“自毁原件”的终极奥义

Authors
  • avatar
    Name
    bin | Rust & SyncGet
    Twitter
    @x

🦀 Bin 的 Rust 毕业笔记:异步并发重型发动机拆解

这是我花了一下午,死磕 4 小时拆出来的“带毒”代码。我不学死语法,我只拆逻辑。这篇笔记记下了我是怎么把 Rust 最硬核的内存所有权和并发通信给“玩死”的。


1. 任务回执单:总部的标准协议 (The Result)

type JobResult<T> = Result<T, Box<dyn Error + Send + Sync>>;

# 🦀 BinRust 毕业笔记:异步并发重型发动机拆解

这是我花了一下午,死磕 4 小时拆出来的“带毒”代码。我不学死语法,我只拆逻辑。这篇笔记记下了我是怎么把 Rust 最硬核的内存所有权和并发通信给“玩死”的。

---

## 1. 任务回执单:总部的标准协议 (The Result)

```rust
type JobResult<T> = Result<T, Box<dyn Error + Send + Sync>>;
  • 我的理解:这就是一张**“任务回执单”**。
  • 泛型 T:就是我要带回来的货。抓网页它就是 String,测数据它就是数字。
  • Box<dyn Error>“全能保险盒”。不管出什么乱七八糟的错(信号断了、货丢了),通通给我丢进这个动态盒子里。
  • Send + Sync:报错单的**“安检证”**。确保这个错误能在不同小哥手里传来传去(Send),而且大家都能看这份事故报告(Sync)。

2. 小哥的武功秘籍:结构与动作 (Impl & Run)

type Hdc = HeavyDutyCrawler; // 太长记不住,我给它起个简名

struct Hdc {
    id: usize // 给小哥办个工牌,兼容 32/64 位机器
}

impl Hdc {
    async fn run(&self, tx: mpsc::Sender<String>) -> JobResult<()> {
        let data = format!("来自 {} 号小哥的爬虫数据", self.id);
        tx.send(data).await.map_err(|bug| bug.into())
    }
}
  • async:异步不傻等。老板要白菜,小哥去买菜,好了喊老板,中间老板可以去泡茶,不准在那排队等死。
  • &self“借钥匙”。干活得拿钥匙开门,但干完得还给主人。不加 & 钥匙就跟着小哥一起报废了。
  • tx: mpsc::Sender:单兵装备的**“对讲机”**(发射端)。买到货了(String),按一下 tx 喊话总部。
  • .map_err(|bug| bug.into())“事故处理车间”|| 是陷阱,专门抓 bug;into() 是万能翻译官,把小哥的土话翻译成总部能听懂的标准报告。

3. 指挥部:多兵种作战 (Main & JoinSet)

#[tokio::main] // 挂了奥迪引擎的指挥部
async fn main() -> JobResult<()> {
    let (tx, mut rx) = mpsc::channel(32); // 32 个坑位的传送带
    let mut station = tokio::task::JoinSet::new(); // 建立点将台

    for i in 0..10 {
        let tx_clone = tx.clone(); // 关键:复印对讲机
        station.spawn(async move {
            let worker = Hdc { id: i };
            let _ = worker.run(tx_clone).await; // 忽略小报告,因为货已经走 tx 传回了
        });
    }

    // 【灵魂一行】自毁原件
    drop(tx);

    while let Some(msg) = rx.recv().await {
        println!("【入库成功】: {}", msg);
    }

    Ok(()) // 分毛不要,体面收工
}

🧠 Bin 的核心逻辑点:

  1. JoinSet 点将台:这玩意儿牛逼在于可以同时把 10 个兵撒出去,先到先回,指挥部(station)统一调度。
  2. tx.clone() 复印件:Rust 规矩大,东西只能一个人拿。我要派 10 个兵,就得给每人复印一个对讲机(tx_clone),他们才能同时喊话。
  3. async move 搬家命令:把工牌 i 和复印的 tx_clone 彻底塞进小哥怀里。如果不搬家,主人(主线程)走太快,小哥回头一看家伙事儿没了,程序直接当场崩溃。
  4. drop(tx) 自毁原件这是全篇的绝杀。我手里还攥着个原件呢。只要这世上还有一个 tx(原件或复印件)活着,总部的接收端 rx 就会以为“还有人要说话”,就会死等。只有我把原件扔了,小哥们把复印件也扔了,rx 才会死心下班。
  5. while let Some(msg):总部在传送带尽头守着,只要有货(Some)就掏出来入库。

🚩 毕业宣言

我没背过一句 Rust 语法,但我现在知道怎么让 10 个小哥拿着复印的对讲机、带着搬家的家伙事儿、在异步的节奏下、通过自毁原件的方式,把货稳稳当当地送回总部。

Rust 这本书,我算是拆通了。

🦀 进阶:智能指针 Box<T> 允许你将数据明确地存储在堆上。