繁体   English   中英

JS:调用一个函数需要多长时间?

[英]JS: How long does it take to call a function?

因此,我正在编写2D Javascript物理模拟程序。 性能很好,但是我正在进行优化以使其更好。 因此,由于该程序可以处理许多物理几何,因此我在程序中进行了多次勾股定理计算。 总共约有五次计算; 它们总共每秒运行约一百万次。 因此,我认为如果将简单的毕达哥拉斯定理代码放入一个新函数并将其调用,它将提高性能。 毕竟,这样浏览器的编译工作就更少了。 因此,我在Firefox中运行了代码,并得到了...。该计算的执行时间增加了4000000%。

怎么样? 它是相同的代码:Math.sqrt(x * x + y * y),那么如何将其添加为函数会降低速度呢? 我认为原因是一个函数仅在不执行代码的情况下就需要花费时间,并且每秒增加一百万个这样的延迟会减慢它的速度?

这似乎让我感到震惊。 这也适用于预定义的js函数吗? 似乎不太可能,如果是这样,他们如何避免呢?

过去的代码如下:

function x()
{
    dx=nx-mx;
    dy=ny-my;
    d=Math.sqrt(dx*dx+dy*dy);
    doStuff(...
}

我试过的是:

function x()
{
    dx=nx-mx;
    dy=ny-my;
    d=hypo(dx,dy);
    doStuff(...
}
function hypo(x,y)
{
    return Math.sqrt(x*x+y*y);
}

谢谢!

在JS从未有过的预编译语言中,函数调用可以忽略甚至优化。 除此之外,很大程度上取决于浏览器。

它们是JS直到最近才出现的所有解释语言性能的牺牲品。 大多数现代浏览器都具有JIT(Just In Time)编译器,这是对过去JS解释器的巨大升级,但我认为对另一个作用域的函数调用仍会花费一些开销,因为JS的调用对象必须确定实际调用的内容,这意味着沿着各种范围链上下移动。

因此,一般规则是:如果您关心IE8以及较低版本和较低版本的Chrome和Firefox,请避免函数调用期。 特别是内部循环。 对于JIT浏览器,我希望在其他函数中定义的一个函数通常会有所帮助(但我仍会进行测试,因为这是IE9的全新技术,其他人则相对较新)。

另一件事要小心。 如果功能特别复杂,JIT可能不会做任何优化它们的事情。

https://groups.google.com/forum/#!msg/closure-compiler-discuss/4B4IcUJ4SUA/OqYWpSklTE4J

但是要了解的重要一点是,当某些东西被锁定并且仅在上下文中调用时(例如函数中的函数),JIT应该很容易优化。 在函数外部定义,它必须确定确切调用了该函数的哪个定义。 它可以在外部函数中。 它可能是全球性的。 它可能是窗口对象的构造函数原型的属性,等等。在一种函数是第一类的语言中,这意味着它们的引用可以以args的方式传递,就像传递数据的方式一样,您无法避免这一步在当前环境之外。

因此,尝试在X内定义次假设,看看会发生什么。

从解释时代开始的另外两个一般技巧在JIT中可能仍然很有价值:

  • “。” someObject.property operator,是一个值得缓存的过程。 每次您都要使用关联的调用对象查找过程,因此会产生开销。 我想Chrome不会保留此过程的结果,因为对父对象或原型的更改可能会更改其在给定上下文之外实际引用的内容。 在您的示例中,如果x被循环使用(如果x与JIT中的循环在同一函数中定义-解释器中的谋杀)可能很好,甚至有帮助,我会在使用它之前尝试将Math.sqrt分配给var在假设中。 在当前函数的上下文之外对事物的引用过多,可能会导致某些JIT认为优化不值得麻烦,但这纯粹是我的猜测。

  • 以下可能是循环数组的最快方法:

 //assume a giant array called someArray var i = someArray.length; //note the property lookup process being cached here //'someArray.reverse()' if original order isimportant while(i--){ //now do stuff with someArray[i]; } 

注意:由于某些原因,代码块在这里无法正常工作。

这样做很有帮助,因为它基本上将inc / decrecrement步骤和逻辑比较变成了只有decrement的形式,从而完全消除了对left / right比较运算符的需求。 请注意,在JS中,右侧的减量运算符意味着我要传递给求值对象,然后递减,然后在块内使用它。 while(0)计算结果为false。

令我惊讶的是,按照Erik的建议缓存查找对提高我的浏览器(Chromium,Linux)的性能并没有多大帮助,但反而似乎损害了性能: http : //jsperf.com/inline-metric-distance

var optimizedDistance = (function () { 
    var sqrt = Math.sqrt;
    return function (x, y) { return sqrt(x * x + y * y); }
})();

var unoptimizedDistance = function(x, y) {
    return Math.sqrt(x * x + y * y);
}

即使调用别名也较慢

var _sqrt = Math.sqrt; // _sqrt is slower than Math.sqrt!

但是话又说回来,这并不是一门精确的科学,现实生活中的测量结果仍可能有所不同。

尽管如此,我还是会使用Math.sqrt

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM