动手
前面十章读的是 rayon 怎么做。这一部分反过来,用最少的代码把三个核心机制自己写一遍,再确认删掉某一行会错。页面只放思路和关键片段,完整代码在 exp-rayon/hands-on/:src/pool.rs(线程池、job、latch、睡眠)、src/join.rs、src/splitter.rs,三个可执行程序 src/bin/{lost_wakeup,fib,splits}.rs 和 tests/mini.rs。依赖只有 crossbeam-deque =0.8.8(Worker / Stealer / Injector),外加 rayon =1.12.0 只用来在同一个进程里并排数叶子。所有片段都从这些文件里摘出,编译、测试都跑过(本机 M2 Max,8 性能核 + 4 能效核,rustc 1.99.1,--offline --release)。
- 最小工作窃取线程池:每线程一个 LIFO
Worker,找活顺序本地、偷别人、注入队列;整个池一把锁、一个Condvar,睡前「加锁、登记、fence、复查」。压力测试 10 次全过;去掉复查,10 次全部卡死。 - 最小 join:B 是栈上 job 加一个
SpinLatch,先推 B 再跑 A,弹回 B 就内联,被偷了就边等边干活;Latch::set取裸指针,set 之前读出要用的东西。fib 结果正确;改成直接阻塞在 latch 上,嵌套join一多就卡死;弹回 B 但不偷不会死锁,只是慢。 - 最小自适应 Splitter:rayon 的三行 thief-splitting 接在 mini
join_context上。1、2 线程的叶子数与 rayon 逐个相同(池外 8 / 16、池内 2 / 4);忽略migrated后叶子数钉死在 2 的幂。
flowchart TB pool["最小线程池"] --> find["find_work:本地 → 偷 → 注入"] pool --> slp["sleep:加锁 → 登记 → fence → 复查 → wait"] slp --> rev1["反向:去掉复查 → 10/10 卡死"] join["最小 join"] --> sj["栈上 StackJob + SpinLatch"] sj --> wu["弹回 B 内联,或 wait_until 边等边干活"] wu --> rev2["反向:直接阻塞 → 卡死;不偷 → 变慢"] spl["最小 Splitter"] --> mig["migrated 来自 join_context"] mig --> rev3["反向:忽略 migrated → 叶子数钉死"] pool --> join join --> spl
怎么跑
cd exp-rayon/hands-on
cargo test --offline --release # fib、多线程 install、migrated 标志、1 线程叶子数
cargo run --offline --release --bin lost_wakeup -- 2 4 200000 10
cargo run --offline --release --bin fib -- 12 36 15 5
cargo run --offline --release --bin splits -- count 12 1048576 5
# 反向验证,各用一个 feature,建议各给一个 --target-dir 免得来回重编
cargo run --offline --release --features no_recheck --bin lost_wakeup -- 2 4 200000 10
cargo run --offline --release --features block_wait --bin fib -- 2 30 27 1 5
cargo run --offline --release --features no_steal_wait --bin fib -- 12 36 15 5
cargo run --offline --release --features ignore_migrated --bin splits -- count 12 1048576 5
卡死类的反向验证都带看门狗:超时打印进度并以退出码 3 退出,不会挂住终端。
和课程的关系
三个实现刻意省掉了很多:没有 panic 传播(任何 panic 都 abort)、没有 scope / spawn / broadcast、没有跨池、睡眠只有一把全池的锁、Splitter 没有 producer / consumer。每一页末尾列出了省掉的部分和 rayon 对应的做法。把它们补全是课程的内容;本卷只保证骨架是对的,并且能说出复查、fence、「set 之后不碰」、migrated 各防的是什么。
💬 关联讨论
发起讨论加载中...