为什么在计算素数的总和时,nodejs比生锈要快



我编写了一个基准测试,该基准计算出第一个10000个素数的总和,并将Rust与JavaScript进行了比较。Nodejs上的JavaScript是Rust,Scala和Java中最快的。即使该程序有意使用功能样式来测试旨在显示Rust零成本抽象的优势的原始性,但Nodejs还是击败了它们。

nodejs是一个动态打字运行时,如何快?

生锈代码

fn sum_primes(n: usize) -> u64 {
    let mut primes = Vec::new();
    let mut current: u64 = 2;
    let mut sum: u64 = 0;
    while primes.len() < n {
        if primes.iter().all(|p| current % p != 0) {
            sum += current;
            primes.push(current);
        }
        current += 1;
    }
    sum
}

JavaScript代码

function sumPrimes(n) {
    let primes = [];
    let current = 2;
    let sum = 0;
    while (primes.length < n) {
        if (primes.every(p => current % p != 0)) {
            sum += current;
            primes.push(current);
        }
        ++current;
    }
    return sum;
}

可以在GitHub上找到完整的基准。

答案不能简单,因为v8对转换的 lot ,但这是一个主要点:

节点的优化编译器会动态调整其使用的类型(尤其是对于数组元素)。它可以使用一个单词整数时使用(并在接收非拟合值时deoptimize )。

如果我按照您的功能,当节点仅需1.04ms(在加热后)时,生锈的人需要1.28ms来计算sum_prime(500)。如果我将u64更改为锈谱中的u32,则仅需608µs。


我使用的JavaScript代码:

function sum_primes(n) {
    var primes = [];
    var current = 2;
    var sum = 0;
    while (primes.length < n) {
        if (primes.every(function (p) { return current % p != 0; })) {
            sum += current;
            primes.push(current);
        }
        ++current;
    }
    return sum;
}
console.log(sum_primes(200));
// some warming
for (let i=0; i<100; i++) sum_primes(100);
console.time("primes");
console.log(sum_primes(500));
console.timeEnd("primes");

此JavaScript代码比您的Rust Code快,但比此较慢:

use std::time::Instant;
fn sum_primes(n: usize) -> u32 {
    let mut primes = Vec::new();
    let mut current: u32 = 2;
    let mut sum: u32 = 0;
    while primes.len() < n {
        if primes.iter().all(|p| current % p != 0) {
            sum += current;
            primes.push(current);
        }
        current += 1;
    }
    sum
}
fn main() {
    println!("{}", sum_primes(200));
    let s = Instant::now();
    println!("{}", sum_primes(500));
    println!("duration: {:?}", s.elapsed());
}

我认为您的基准有些缺陷,因为即使在编译时(即prepack,closure),即使在编译时,足够高级的编译器也可以将sum_primes(10000)优化到496165411中。也可以在运行时第一次通话后记住结果,这可能是V8所做的(尽管我希望Hotspot会做同样的事情)。

使用一个在编译时间而不是10000的值,例如命令行参数。

相关内容

  • 没有找到相关文章

最新更新