我是node.js的新手。
我试图将70000个项目插入数组,然后删除所有项目:
var Stopwatch = require("node-stopwatch").Stopwatch;
var stopwatch = Stopwatch.create();
var a = []
stopwatch.start();
for (var i = 1 ; i < 70000 ; i++){
a.push((parseInt(Math.random() * 10000)) + "test");
}
for (var i = 1 ; i < 70000 ; i++){
a.splice(0,1);
}
stopwatch.stop();
console.log("End: " + stopwatch.elapsedMilliseconds + " : " + a.length);
工作正常,输出为:
PS C:\Users\Documents\VSCode> node test.js
End: 51 : 0
但是当我将项目数量增加到72000时,结束需要花费太多时间:
var Stopwatch = require("node-stopwatch").Stopwatch;
var stopwatch = Stopwatch.create();
var a = []
stopwatch.start();
for (var i = 1 ; i < 72000 ; i++){
a.push((parseInt(Math.random() * 10000)) + "test");
}
for (var i = 1 ; i < 72000 ; i++){
a.splice(0,1);
}
stopwatch.stop();
console.log("End: " + stopwatch.elapsedMilliseconds + " : " + a.length);
输出是:
End: 9554 : 0
为什么会这样?只增加了2000个项目,但需要花费太多时间。
Node.js版本是:v6.11.3
答案 0 :(得分:3)
V8开发者在这里。在开始时(array[0]
)删除(或插入)数组元素通常非常昂贵,因为必须移动所有剩余的元素。基本上,对于这些.splice(0, 1)
操作中的每一个,引擎必须做的事情是:
for (var j = 0; j < a.length - 1; j++) {
a[j] = a[j+1];
}
a.length = a.length - 1`
在某些情况下,V8可以在引擎盖的底部使用一个技巧 - 而在快速的情况下,你可以看到这个技巧提供的惊人的加速。但是,由于技术原因,此技巧不能应用于超出特定大小的阵列。由此产生的&#34;减速&#34;实际上是&#34; true&#34;这种非常昂贵的操作的速度。
如果您想快速删除数组元素,请从最后删除它们(array[array.length - 1]
),例如使用Array.pop()
。如果您想一次性删除所有元素,只需设置array.length = 0
即可。如果你需要快速FIFO /&#34;队列&#34;语义,考虑从环形缓冲区中获取灵感:有一个&#34;光标&#34;对于要读取/返回的下一个元素,只有当有大量元素被释放时才收缩数组。大致是:
function Queue() {
this.enqueue = function(x) {
this.array_.push(x);
}
this.dequeue = function() {
var x = this.array_[this.cursor_++];
// Free up space if half the array is unused.
if (this.cursor_ > this.array_.length / 2) {
this.array_.splice(0, this.cursor_);
this.cursor_ = 0;
}
return x;
}
this.array_ = [];
this.cursor_ = 0;
}
旁注:这并不重要,但为了记录,要将70,000个元素推入数组,您的循环应从0开始:for (var i = 0; i < 70000; i++) {...}
。如上所述,你只推动了69,999个元素。
附注2:通过&#34; parseInt&#34;将double舍入为整数非常慢,因为它首先将double格式化为字符串,然后将该字符串作为整数读回。更快的方法是Math.floor(Math.random() * 10000))
。 (出于本次测试的目的,您也可以简单地推送i
。)
答案 1 :(得分:0)
有趣的是,我做了类似
的事情if (i % 1000 === 0) {
console.log(i + " " + stopwatch.elapsedMilliseconds + " : " + a.length);
}
在第二个循环内。 (这很难计算,但它有助于诊断问题)
我没有遭受性能损失。但是,我认为,我找到了为什么&#34;只有&#34; 2000更多的事情要做的就是节点很难。首先 - 我的区别: [loop max num,unit,3 benchmarks results]
70k:[ms] ~26k,~25.7k,~26k 72k:[ms] ~25.6k,27k,25.7k
好的,当我看到日志记录时,我看到,最后的10k记录就像瞬间计算一样。我认为splice
从前面移除1个项目,然后 - 逐个移动数组1索引&#34;到开始&#34;,让我们将测试更改为10个数组10k记录,看它是否会好得多。我会以最懒惰的方式做到这一点:
var Stopwatch = require("node-stopwatch").Stopwatch;
var stopwatch = Stopwatch.create();
var a1 = [], a2 = [], a3 = [], a4 = [], a5 = [];
var a6 = [], a7 = [], a8 = [], a9 = [], a10 = [];
stopwatch.start();
function fill (arr) {
for (var i = 1 ; i < 10000 ; i++){
arr.push((parseInt(Math.random() * 10000)) + "test");
}
}
fill(a1); fill(a2); fill(a3); fill(a4); fill(a5);
fill(a6); fill(a7); fill(a8); fill(a9); fill(a10);
let removeCount = 0;
function unfill(arr) {
for (var i = 1 ; i < 10000 ; i++){
arr.splice(0,1);
removeCount++;
if (i % 1000 === 0) {
console.log(i + " " + stopwatch.elapsedMilliseconds + " : " + arr.length);
}
}
}
unfill(a1); unfill(a2); unfill(a3); unfill(a4); unfill(a5);
unfill(a6); unfill(a7); unfill(a8); unfill(a9); unfill(a10);
stopwatch.stop();
console.log("End: " + stopwatch.elapsedMilliseconds + " removeCount " + removeCount);
而且,是的...我没有回答为什么你的电脑在70k到72k的记录之间有这样的性能损失 - 我相信它是依赖于机器的......可能缺少RAM,但是没有得到它错了 - 我不知道。
我解决了如何改善这一点。 10个阵列上的100k(-10)执行时间约为73-74毫秒。我认为,您可以将其写入2d数组并修改逻辑以根据需要计算长度和剩余部分。
感谢您的关注。