我编写了一个基准测试,计算前10000个素数的总和,并将其与JavaScript进行比较.NodeJS上的JavaScript在Rust、Scala和Java中速度最快.尽管这些程序有意使用函数风格来测试素性,以展示Rust的零成本抽象的优势,但NodeJS胜过了所有这些.

NodeJS,一个动态输入运行时,怎么能这么快?

Rust code

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 code

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;
}

完整的基准可以在on GitHub中找到.

推荐答案

答案并不简单,因为V8进行了lot次转换,但这里有一个要点:

Node的优化编译器动态地调整它使用的类型(尤其是数组元素).它能够在合适的时候使用一个字的整数(当函数接收到不合适的值时使用deoptimizes个字的整数).

如果我按照你的函数的原样来理解,Rust one需要1.28ms来计算sum_prime(500),而Node只需要1.04ms(经过一些升温).如果我将 rust 代码中的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代码快,但比下面的代码慢:

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());
}

Rust相关问答推荐

有没有方法处理rust中嵌套的ok_or()?

什么是Rust惯用的方式来使特征向量具有单个向量项的别名?

为什么`Vec i64`的和不知道是`Option i64`?

使用模块中的所有模块,但不包括特定模块

为什么Rust函数的移植速度比C++慢2倍?

通过使用光标拖动角来绕其中心旋转矩形

当第二个`let`依赖于第一个`let()`时,如何在一行中有多个`let()`?

为什么reqwest以文本形式下载二进制文件?

如何提高自定义迭代器的`extend`性能

integer cast as pointer是什么意思

闭包不会发送,即使它只捕获发送变量

如何在Rust中基于字符串 Select struct ?

通过异常从同步代码中产生yield 是如何工作的?

需要一个有序向量来进行 struct 初始化

Rust并发读写引起的死锁问题

没有得到无法返回引用局部变量`queues`的值返回引用当前函数拥有的数据的值的重复逻辑

使用 rust 在 google cloud run (docker) 中访问环境变量的适当方法

为什么在 rust 中删除 vec 之前应该删除元素

隐式类型闭包的错误生命周期推断

如何为枚举中的单个或多个值返回迭代器