关于Nodejs性能,一个奇怪的问题

关于Nodejs性能,一个奇怪的问题

测试一: 代码: var t = Date.now(); var a = 0; var test_fun_1 = function() { for( var j = 0; j < 1000000; j++ ) { a += j; } }; for( var i = 0; i < 100; i ++ ) { test_fun_1(); } 测试方法: 分别把i的值设置为100,200,300,400,用i的值除以最后打印出的时间,即得到每秒执行test_fun方法的次数,分别为:67,69,69,70 总得说来差不多

测试二: var t = Date.now(); var a = 0; var test_fun_2 = 我封装的一个方法,比较复杂,有着js内的各种操作,这个方法每次运行都一样; for( var i = 0; i < 100; i ++ ) { test_fun_2(); } 分别把i的值设置为100,200,300,400,用i的值除以最后打印出的时间,即得到每秒执行test_fun方法的次数,分别为:192,78,42,26

问题: 通过测试一可以看出,如果只是单纯的计算,平均值不会随着计算的增多而变化。 测试二明显随着i的增大,每秒执行方法的次数是越来越小,导致这样的结果的原因有哪些?


9 回复

关于Node.js性能,一个奇怪的问题

在Node.js中,性能优化是一个重要的话题。最近我遇到了一个有趣的问题,这个问题涉及到不同情况下函数调用的性能差异。为了更好地理解这个问题,我设计了两个简单的测试用例。

测试一:单纯计算

首先,我们来看一个简单的测试,该测试只涉及基本的数学运算:

var t = Date.now();
var a = 0;

var test_fun_1 = function() {
    for (var j = 0; j < 1000000; j++) {
        a += j;
    }
};

for (var i = 0; i < 100; i++) {
    test_fun_1();
}

console.log(`Time taken: ${Date.now() - t} ms`);

在这个测试中,我们定义了一个简单的函数 test_fun_1,它执行了100万次加法操作。然后我们循环调用该函数100次,并记录时间。通过多次调整循环次数(例如100, 200, 300, 400),并计算每秒执行的次数,我们发现结果非常稳定,约为每秒67到70次。

测试二:复杂操作

接下来,我们来看一个更复杂的测试,其中包含了一些JavaScript中的各种操作:

var t = Date.now();
var a = 0;

var test_fun_2 = function() {
    // 这里可以是一些复杂的操作,例如数组操作、对象操作等
    // 示例代码:
    let arr = [];
    for (let k = 0; k < 1000; k++) {
        arr.push(k);
    }
    arr.forEach(item => {
        if (item % 2 === 0) {
            a += item;
        }
    });
};

for (var i = 0; i < 100; i++) {
    test_fun_2();
}

console.log(`Time taken: ${Date.now() - t} ms`);

在这个测试中,我们定义了一个更复杂的函数 test_fun_2,它包含了数组的创建和遍历操作。同样地,我们循环调用该函数100次,并记录时间。然而,这次的结果显示出明显的性能下降,每秒执行的次数从192下降到26。

问题分析

通过对比这两个测试,我们可以得出以下结论:

  1. 简单计算:在测试一中,由于操作非常简单,性能几乎不受循环次数的影响。这是因为Node.js引擎能够很好地优化这种简单的循环操作。

  2. 复杂操作:在测试二中,由于操作更加复杂,每次调用函数时需要进行更多的计算和内存操作。这导致了性能的显著下降,因为每次调用函数时都需要重新分配内存和执行额外的操作。

结论

这个问题提醒我们在编写Node.js应用时需要注意性能瓶颈。简单操作通常会被Node.js引擎很好地优化,而复杂的操作则可能带来显著的性能损失。因此,在实际开发中,我们应该尽量减少不必要的复杂操作,优化算法,以提高应用的整体性能。

希望这些测试和分析对你有所帮助!如果你有其他疑问或需要进一步的帮助,请随时提问。


test_fun_2里面都做了一些什么操作呢 可能挟持了一些资源没有释放吧 没有代码 我也不敢乱猜 不过估计应该是你那个方法的问题

1.里面没有任何io操作,没有操作文件,没有操作数据库。 2.就是纯计算,有个类,然后实例化出来很多对象,每个对象有着自己的属性,比如血量,攻击力,然后就是一个循环,模拟这些事例打斗,直到有一方胜利。 3.基本上就是些计算,数组操作,实例化对象

可能v8引擎有记忆棒功能,以前做过类似的,可以为一些常用的函数尤其在大量循环中做记忆存储器的功能,减小性能开销。

如你所说,确实是这样的,V8的缓存很牛b,所以说fast than c

问题找到了,与js自身的一个sort方法有关系,建议大家尽量少使用这个。 它引出来的问题: 1.运算效率以将近9倍左右的时间降低。 2.运行次数越多,时间还会按2倍左右的时间在原基础上降低。

貌似V8的sort函数跟其他引擎的实现方式不一样

根据你的描述,测试二中每秒执行方法的次数随着循环次数的增加而减少,这可能是由于以下几个原因:

  1. 内存占用:如果你的方法test_fun_2涉及复杂的操作,可能会产生大量的临时对象。当循环次数增加时,垃圾回收器(GC)需要处理更多的垃圾对象,从而增加了额外的开销。

  2. CPU调度:Node.js是单线程的,当某个任务占用大量CPU时间时,其他任务可能需要等待,导致整体执行效率降低。

  3. 编译和优化:V8引擎会对JavaScript代码进行即时编译(JIT)。不同长度的循环可能会影响编译和优化的过程,导致执行速度的变化。

  4. 系统负载:如果你的机器上同时运行着其他程序,系统负载可能会导致Node.js进程被分配到较少的CPU时间片,从而影响执行效率。

示例代码

假设test_fun_2方法如下:

var test_fun_2 = function() {
    for (var j = 0; j < 1000000; j++) {
        // 假设这里有一些复杂的操作
        let obj = { a: j, b: j * 2 };
        a += obj.a + obj.b;
        // 模拟一些额外的操作
        if (j % 1000 === 0) {
            console.log(`Intermediate: ${a}`);
        }
    }
};

测试代码

function runTest(i) {
    const t = Date.now();
    let a = 0;

    for (let k = 0; k < i; k++) {
        test_fun_2();
    }

    const timeTaken = Date.now() - t;
    console.log(`For i=${i}, time taken: ${timeTaken} ms`);
    console.log(`Operations per second: ${i / (timeTaken / 1000)}`);
}

runTest(100);
runTest(200);
runTest(300);
runTest(400);

解释

  • 内存管理:如果test_fun_2中创建了大量的临时对象,垃圾回收器会在循环结束后清理这些对象,这会增加额外的开销。
  • 复杂操作test_fun_2中的复杂操作会导致CPU利用率增加,从而影响整体性能。
  • 日志输出console.log等输出操作也会消耗一定的时间,尤其是在循环内部频繁调用时。

你可以尝试优化test_fun_2方法,减少不必要的对象创建和复杂操作,看看是否能改善性能。

回到顶部