rayon 让「把 iter 改成 par_iter」成为可能,但到底能快多少?什么时候反而更慢?线程数怎么影响?闭包里能不能随便改共享状态?这篇每个问题都在本机跑出数字。
(含下载编译 rayon,用时 2 s) 可用并行度 10 rayon 线程数 10 par_iter().map().collect() 保持原顺序: true par_iter().sum() = 210 iter().sum() = 210 for_each 里的执行顺序按 0..16 排好: false(并行执行,顺序不保证);内容齐全: true
rayon 1.x 从 crates.io 下载(需要联网)。线程的基础见线程创建与 Join。
串行 iter 57.2 ms 结果 186.509301 并行 par_iter 8.9 ms 结果 186.509301 加速 6.4× 浮点求和的结果在小数点后 9 位一致(并行的加法顺序不同)
n= 100: 串行 0.01 µs 并行 20.84 µs 串行更快 n= 10000: 串行 0.73 µs 并行 41.80 µs 串行更快 n= 1000000: 串行 88.15 µs 并行 90.22 µs 串行更快 n= 100000000: 串行 25725.89 µs 并行 6468.01 µs 并行更快
线程数 1: 28.5 ms 相对 1 线程 1.0× 线程数 2: 14.3 ms 相对 1 线程 2.0× 线程数 4: 7.5 ms 相对 1 线程 3.8× 线程数 8: 4.8 ms 相对 1 线程 5.9× 线程数 10: 4.6 ms 相对 1 线程 6.2×
par_iter + Mutex 110.97 ms 结果 12499997500000 par_iter + reduce 0.65 ms 结果 12499997500000 串行 sum 0.76 ms 结果 12499997500000
Mutex 的开销见Mutex 与 RwLock。
error[E0277]: `RefCell<i32>` cannot be shared between threads safely
--> src/main.rs:2:70
|
2 | fn main() { let c = RefCell::new(0); (0..4).into_par_iter().for_each(|i| { *c.borrow_mut() += i; }); }
| -------- ---^^^^^^^^^^^^^^^^^^^^^^^^^^
| | |
| | `RefCell<i32>` cannot be shared between threads safely
| | within this `{closure@src/main.rs:2:70: 2:73}`
| required by a bound introduced by this call