wasm VS js,谁快?(七)重构

781 阅读2分钟

风起提示:由于技术的发展风起云涌,需留意文章时效,2023-06-28。

回顾

开始新内容前让我们先回忆下之前的内容,之前我们构造了一棵约30万个节点的树,测出来结果 wasm比js慢约4倍,比较反直觉,所以我们拆分成:循环、对象深拷贝、向量切片、数学函数、向量的插入和删除,对这几部分分别测试,看看到底哪里慢了。

上一章我们发现wasm比js慢在向量的头部删除上,改用双端队列后性能大幅提升,这次我们重构下第一次尝试的代码看看效果。

重构

用双端队列及向量原始指针重构树的构建

rust代码

#[wasm_bindgen]
#[derive(Clone)]
pub struct Item {
    name: String,
    children: Vec<Item>,
}

#[wasm_bindgen]
pub fn unsafeTreeFun(treeLevel: u32, nodeWidth: u32) -> Item {
    let tempNode = Item {
        name: String::from(""),
        children: vec![],
    };

    let mut root = tempNode.clone();
    root.name = String::from("node_0_0");

    if treeLevel < 2 {
        return root;
    }

    let mut nodeStack: VecDeque<&mut Item> = VecDeque::new();

    for m1 in 0..nodeWidth {
        let mut curItem = tempNode.clone();
        curItem.name = format!("node_{}_{}", 1, m1);
        root.children.push(curItem);
    }

    let ptr1 = root.children.as_mut_ptr();
    unsafe {
        for m2 in 0..nodeWidth {
            nodeStack.push_back(&mut *ptr1.add(m2.try_into().unwrap()));
        }
    }

    for i in 2..treeLevel {
        let curTotal: u32 = nodeWidth.pow(i - 1);

        for j in 0..curTotal {
            let shiftItem = nodeStack.pop_front().unwrap();

            for k1 in 0..nodeWidth {
                let mut curItem = tempNode.clone();
                curItem.name = format!("node_{}_{}", i, nodeWidth * j + k1);
                shiftItem.children.push(curItem);
            }

            let ptr2 = shiftItem.children.as_mut_ptr();
            unsafe {
                for k2 in 0..nodeWidth {
                    nodeStack.push_back(&mut *ptr2.add(k2.try_into().unwrap()));
                }
            }
        }
    }

    root
}

js代码参考第一次尝试里的,这里没有变。

结论

还是一个7层深度,每个节点下8个子节点共299593个节点的树,执行结果

total nodes:  299593
wasm-deq-tree: 347.54443359375 ms
js-tree: 7232.81201171875 ms

最终可以看到wasm快的多,对于树的构建速度大概是js的20倍。

总结

这里测试只考虑wasm和js的执行速度,排除了wasm和js传递大量数据的场景,只是纯粹的体验下wasm的执行速度。

通过这个测试了解到,wasm从设计机制上确实比js运行得快,如果发现不快就要开始反思,是不是可以优化。

我们还发现js追求的是灵活方便,对底层数据结构做了很多封装和优化。rust追求的是性能稳定,提供了细粒度且严格的内存及数据结构控制。两种语言设计初衷不一样。

至于wasm和js的传参,需要了解wasm的内存模型,下次我们介绍。

更多精彩内容可关注风起的博客,微信公众号:听风说图