Rayon find_any找到解后其余线程仍运行的优化问询
优化并行暴力破解离散对数的线程终止逻辑
首先翻译Rayon官方文档中关于find_any的描述:
在并行迭代器中搜索符合给定断言的元素并返回它。这个操作类似顺序迭代器上的
find,但由于是并行搜索整个序列,返回的元素可能不是序列中第一个符合条件的。一旦找到匹配项,我们会尽快尝试停止处理迭代器中的其余元素(就像
find找到匹配项后立即停止迭代一样)。
你的问题核心在于:find_any只能停止迭代器中未开始执行的任务,但无法中断已经在运行的线程内部的循环。每个线程的while循环会一直执行到结束,直到自己的chunk遍历完,即使其他线程已经找到结果。
优化方案
- 使用**原子布尔值(AtomicBool)**作为全局终止标志,线程可以无锁快速检查是否已找到结果
- 优化幂次计算:避免每次调用
modpow,改为逐步乘积累加,大幅提升计算效率
以下是修改后的代码:
use num_bigint::BigUint; use num_traits::One; use rayon::prelude::*; use std::sync::{Mutex, atomic::{AtomicBool, Ordering}}; fn main() { let p = BigUint::parse_bytes("531137992816767098689588206552468627329593117727031923199444138200403559860852242739162502265229285668889329486246501015346579337652707239409519978766587351943831270835393219031728127" .as_bytes(), 10).unwrap(); let g = BigUint::parse_bytes("743488989946216334211646350465118756727157777337013657445667148279632819469843031446430723942629760903918287800011367316376" .as_bytes(), 10).unwrap(); let y = BigUint::parse_bytes("85300193795644893333630947242400469685524126293619036977651049331711403849653080708338436527820826037193273430333874138094661788038445049976895820193634304228963983382234907450594225" .as_bytes(), 10).unwrap(); println!("g: {}", g); println!("y: {}", y); // Brute force y = g^x let size = BigUint::from(2u32).pow(20); let num_cores = 8 as usize; let chunk_size = &size / num_cores; let found = AtomicBool::new(false); let num = Mutex::new(None); (0..num_cores) .into_par_iter() .find_any(|&core_idx| { let start = chunk_size.clone() * core_idx; let end = if core_idx == num_cores - 1 { size.clone() } else { start.clone() + chunk_size.clone() }; // 预计算当前chunk的起始幂次,之后逐步累加 let mut current = g.modpow(&start, &p); let mut x = start.clone(); while x < end && !found.load(Ordering::Relaxed) { if current == y { found.store(true, Ordering::Relaxed); *num.lock().unwrap() = Some(x.clone()); println!("Found x: {}", x); return true; } // 逐步计算下一个幂次,比modpow高效得多 current = (¤t * &g) % &p; x += BigUint::one(); } false }); if let Some(x) = num.lock().unwrap().clone() { println!("Found num: {}", x); } else { println!("x not found in the specified range."); }; }
关键优化点说明
- 原子终止标志:
AtomicBool的load和store操作是无锁的,线程可以快速检查是否需要终止循环,避免不必要的计算 - 幂次累加优化:每个线程只在起始位置调用一次
modpow,之后每次迭代只做一次乘法和取模,计算效率提升几个数量级(modpow是O(log n)复杂度,累加是O(1)) - 立即终止:一旦某个线程找到结果,会立即设置
found为true,其他线程在下一次循环检查时就会退出,不会继续无效计算
内容的提问来源于stack exchange,提问作者m0ur
相关产品推荐
相关产品推荐

