< 返回版块

zhu-zk 发表于 2025-05-15 21:29

Tags:请问下面的两行代码,为什么使用代码并行后,运行时间比没有使用代码并行的时间高出10倍数呢?

使用rust的rayon库函数。

1,rayon库函数优化代码:

fn build_merkle_tree(root: Arc<Mutex<Vec<usize>>>, vect:Vec<usize>, k: Arc<AtomicUsize>, p:usize,q:usize) {
     
    let root_clone = Arc::clone(&root);
    let k_clone = Arc::clone(&k);
    let temp:Vec<_> = vect.par_chunks(2).enumerate().filter_map(|(i,vect_num)| {
        
        let mut root_new = root_clone.lock().expect("出错了");
        let  i = i * 2;
        if i == vect.len()-1 || i == vect.len() -2   {    
            let current_k = k_clone.fetch_add(1, Ordering::SeqCst);                      
            if current_k>=p && current_k<=q  {
                root_new[current_k] = vect_num[0]; 
                }
            }
        if i < vect.len()-1 {
            
            return Some(Hash(vect_num[0],vect_num[1]))
        } else {
            return None;
        }   
    }).collect();

    if !temp.is_empty() {      
        build_merkle_tree( root, temp, k, p,q)
    } else {
            return ;
    }
      
}


2,未使用多线程优化代码。

fn build_merkle_tree_two(root: &mut Vec<usize>, vect:&Vec<usize>, mut k: usize, p:usize,q:usize) -> usize{
    if vect.len() == 0 {
       return k;
    }

    let mut temp = Vec::new();
    for i in (0..vect.len()).step_by(2) {
        if i == vect.len()-1 ||  i == vect.len() -2 {
            root[k] = vect[i];
            k +=1;
        }
        if i < vect.len()-1 {
            temp.push(Hash(vect[i],vect[i+1]));
        }
    }
    k = build_merkle_tree_two( root, &temp, k, 0,0);
    return k;
}

评论区

写评论
xiaoyaou 2025-05-16 12:12

问题已经被指出来了,就是:

锁的生存期太长了,导致整个任务都是卡住的,结果最终还是串行计算,可以调整锁的位置

虽然在你现有代码上,可以严格限制锁周期来缓解性能问题,但是我没太懂,你调用方是需要root的完整数据用来做什么吗。

不清楚你传的初始rootk是什么,以及你想要利用参数传值的方式在调用方使用root里什么数据, 不过因为你用的Vec<..>结构很明显在并行任务里因为共享问题严重限制了并行度

所以优化方式只能是拆解root结构,尽可能让并行任务不要彼此互斥加锁。

简单解读你的代码,看着不像是想要返回构建完整的默克尔树节点的,如果你只是需要根值的话,root就感觉没必要了。建议使用return的方式返回值,而不是在参数里返回,可能有助于你更好的拆解任务

--
👇
zhu-zk:

asuper 2025-05-16 10:28
  1. 锁的生存期太长了,导致整个任务都是卡住的,结果最终还是串行计算,可以调整锁的位置:
    let temp:Vec<_> = vect.par_chunks(2).enumerate().filter_map(|(i,vect_num)| {
        
        // let mut root_new = root_clone.lock().expect("出错了");
        let  i = i * 2;
        if i == vect.len()-1 || i == vect.len() -2   {    
            let current_k = k_clone.fetch_add(1, Ordering::SeqCst);                      
            if current_k>=p && current_k<=q  {
                // 移动到这里
                let mut root_new = root_clone.lock().expect("出错了");
                root_new[current_k] = vect_num[0]; 
                }
            }
        if i < vect.len()-1 {
            
            return Some(Hash(vect_num[0],vect_num[1]))
        } else {
            return None;
        }   
    }).collect();
``

2. 这个任务的计算量可能太小了,并行化中的调度开销可能会超过并行带来的速度提升
3. 我看你这个算法本身就不适合并行
作者 zhu-zk 2025-05-15 22:25

大佬,可以帮忙修改一下代码吗,非常感谢。

--
👇
xiaoyaou: 虽然不了解默克尔数的具体细节,但是你写的并行计算,显然因为每个任务都需要独占唯一的root: Arc<Mutex<..>>锁,所以并的并不是很行[doge]

xiaoyaou 2025-05-15 22:22

虽然不了解默克尔数的具体细节,但是你写的并行计算,显然因为每个任务都需要独占唯一的root: Arc<Mutex<..>>锁,所以并的并不是很行[doge]

1 共 4 条评论, 1 页