我使用kmean算法聚集了大约40000点.在程序的第一个版本中,我像这样编写了欧几里德距离函数
var euclideanDistance = function( p1, p2 ) { // p1.length === p2.length == 3
var sum = 0;
for( var i in p1 ){
sum += Math.pow( p1[i] - p2[i], 2 );
}
return Math.sqrt( sum );
};
Run Code Online (Sandbox Code Playgroud)
整个程序非常缓慢,平均执行时间为7秒.经过一些分析后,我重写了上面这个函数
var euclideanDistance = function( p1, p2 ) { // p1.length === p2.length == 3
var sum = 0;
for( var i = 0; i < p1.length; i++ ) {
sum += Math.pow( p1[i] - p2[i], 2 );
}
return Math.sqrt( sum );
};
Run Code Online (Sandbox Code Playgroud)
现在这些节目平均需要大约400毫秒.由于我编写for循环的方式,这是一个巨大的时间差异.我通常不使用for..in循环数组但由于某种原因我在编写此函数时使用它.
有人可以解释为什么这两种风格之间存在巨大的性能差异吗?
Esa*_*ija 24
看看每次迭代中发生的事情有何不同:
for( var i = 0; i < p1.length; i++ )
Run Code Online (Sandbox Code Playgroud)
i < p1.lengthi一个非常简单快速.
现在看看每次迭代中发生了什么:
重复
- 令P为obj的下一个属性的名称,其[[Enumerable]]属性为true.如果没有这样的属性,则返回(正常,V,空).
它必须在可枚举的对象中找到下一个属性.使用你的数组,你知道这可以通过一个简单的整数增量来实现,其中找到下一个可枚举的算法很可能不那么简单,因为它必须处理任意对象及其原型链键.
作为旁注,如果缓存p1的长度:
var plen = p1.length;
for( var i = 0; i < plen; i++ )
Run Code Online (Sandbox Code Playgroud)
你的速度会略有提高.
...如果您记住该功能,它将缓存结果,因此如果用户尝试相同的数字,您将看到大幅度的速度增加.
var eDistance = memoize(euclideanDistance);
function memoize( fn ) {
return function () {
var args = Array.prototype.slice.call(arguments),
hash = "",
i = args.length;
currentArg = null;
while (i--) {
currentArg = args[i];
hash += (currentArg === Object(currentArg)) ?
JSON.stringify(currentArg) : currentArg;
fn.memoize || (fn.memoize = {});
}
return (hash in fn.memoize) ? fn.memoize[hash] :
fn.memoize[hash] = fn.apply(this, args);
};
}
eDistance([1,2,3],[1,2,3]);
eDistance([1,2,3],[1,2,3]); //Returns cached value
Run Code Online (Sandbox Code Playgroud)
信用:http://addyosmani.com/blog/faster-javascript-memoization/
首先,对于 for/in 和数组,您应该意识到这一点。如果您知道自己在做什么,那没什么大不了的。
我运行了一些非常简单的测试来显示不同循环之间的性能差异:http : //jsben.ch/#/BQhED
这就是为什么更喜欢对数组使用经典的 for 循环的原因。
| 归档时间: |
|
| 查看次数: |
17598 次 |
| 最近记录: |