为什么Node.js比Google Chrome慢得多?

3
我有一个简单的代码,创建了一个16*16*256个盒子,其中每个盒子包含10个元素的数组和一个布尔变量。tick方法会增加数组元素,并在一个chunk中的每个盒子中更改布尔值100次。

通过测量时间,我得出以下结果:
Windows x64 node.js 7.4.0:
1 tick: 102.85
Total time(100): 10285
在同一台机器上使用Google Chrome 55:
1 tick: 18.08
Total time(100): 1808
即使底层代码片段比Node快一个数量级,但是Node还是很慢。
代码片段:
1 tick: 22.79
Total time(100): 2279
那么,我该如何让Node工作更快呢?

(function(){
 class Box {
  constructor() {
   this.data = new Array(10); 
   this.state = false;
  }

  tick() {
   this.state = !this.state;
   for(let i = 0; i < this.data.length; i++) {
    this.data[i]++;
   }
  }
 }

 class Chunk {
  constructor() {
   this.data = new Array(256);

   for(let z = 0; z < this.data.length; z++) {
    this.data[z] = new Array(16);

    for(let x = 0; x < this.data[z].length; x++) {
     this.data[z][x] = new Array(16);

     for(let y = 0; y < this.data[z][x].length; y++) {
      this.data[z][x][y] = new Box();
     }
    }
   }
  }

  tick() {
   for(let z = 0; z < this.data.length; z++) {
    for(let x = 0; x < this.data[z].length; x++) {
     for(let y = 0; y < this.data[z][x].length; y++) {
      this.data[z][x][y].tick();
     }
    }
   }
  }
 }



 var c = new Chunk();
 var count = 100;
 var start = new Date().getTime();

 for(let i = 0; i < count; i++) {
  c.tick();
 }

 var end = new Date().getTime();

 console.log("1 tick: " + (end - start) / count);
 console.log("Total time(" + count + "): " + (end - start));
})();


1
Chrome通常会在每个版本中经常更新V8引擎,那么Node.js使用的是哪个版本呢? - dandavis
在帖子中添加了版本号。 - jDek
1个回答

3

预先填充数组可以在节点中提高一个数量级的性能。

唯一的解释是,在nodejs中,将空数组槽转换为“已使用”槽的“转换”更加昂贵 - 您可以通过从长度-1到0在原始代码中“填充”数组来找到类似的加速(不完全相同但接近)

主要的加速是在Box类中预填充this.data(但这可能是因为在空数组项上使用this.data [i] ++ 655360次)

(function(){
    class Box {
        constructor() {
            this.data = new Array(10).fill(0); 
            this.state = false;
        }

        tick() {
            this.state = !this.state;
            for(let i = 0; i < this.data.length; i++) {
                this.data[i]++;
            }
        }
    }

    class Chunk {
        constructor() {
            this.data = new Array(256).fill(null);

            for(let z = 0; z < this.data.length; z++) {
                this.data[z] = new Array(16).fill(null);

                for(let x = 0; x < this.data[z].length; x++) {
                    this.data[z][x] = new Array(16).fill(null);

                    for(let y = 0; y < this.data[z][x].length; y++) {
                        this.data[z][x][y] = new Box();
                    }
                }
            }
        }

        tick() {
            for(let z = 0; z < this.data.length; z++) {
                for(let x = 0; x < this.data[z].length; x++) {
                    for(let y = 0; y < this.data[z][x].length; y++) {
                        this.data[z][x][y].tick();
                    }
                }
            }
        }
    }





    var c = new Chunk();
    var count = 100;
    var start = new Date().getTime();

    for(let i = 0; i < count; i++) {
        c.tick();
    }

    var end = new Date().getTime();

    console.log("1 tick: " + (end - start) / count);
    console.log("Total time(" + count + "): " + (end - start));
})();

作为补充说明,您的Chunk构造函数可以“简化”为:
this.data = new Array(256).fill([]).map(item => new Array(16).fill([]).map(item => new Array(16).fill([]).map(item => new Box())));

但是这并没有带来更进一步的提升。

我还尝试了在适当的情况下使用.forEach和/或.map,但是任何这样的更改实际上都会使节点的时间减慢约10%。


加速Chrome也是如此,但它们现在几乎相等了!为什么在Node中解包混合类型的数组(null和数字)会造成更大的性能损耗呢? - dandavis
哇!速度快了大约25倍!也许还有另一种创建类和数组的方法可以加速它? - jDek
我已经为你提供了25倍的速度改进(奇怪的是,在我的系统上只有大约10倍,但我的“ticks”大约是6.4),但你想要更多!!! :p - Jaromanda X

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接