Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sql-server-2005/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 性能:开关与多态性_Javascript_Switch Statement_Polymorphism_V8_Vtable - Fatal编程技术网

Javascript 性能:开关与多态性

Javascript 性能:开关与多态性,javascript,switch-statement,polymorphism,v8,vtable,Javascript,Switch Statement,Polymorphism,V8,Vtable,如果可能的话,我通常更喜欢多态性而不是开关。我发现它可读性更强,需要的行更少。我相信这些事实足以继续使用它。但是性能呢?我已经创建了一个非常简单(而且很糟糕)的工作台,看起来在我的情况下切换速度更快。你能解释一下原因吗 var class1={GetImportantValue:()=>1}; var class2={GetImportantValue:()=>2}; var class3={GetImportantValue:()=>3}; var class4={GetImportantV

如果可能的话,我通常更喜欢多态性而不是开关。我发现它可读性更强,需要的行更少。我相信这些事实足以继续使用它。但是性能呢?我已经创建了一个非常简单(而且很糟糕)的工作台,看起来在我的情况下切换速度更快。你能解释一下原因吗

var class1={GetImportantValue:()=>1};
var class2={GetImportantValue:()=>2};
var class3={GetImportantValue:()=>3};
var class4={GetImportantValue:()=>4};
var class5={GetImportantValue:()=>5};
getImportantValueSwitch=(myClassEnum)=>{
开关(myClassEnum.type){
案例“MyClass1”:返回1;
案例“MyClass2”:返回2;
案例“MyClass3”:返回3;
案例“MyClass4”:返回4;
案例“MyClass5”:返回5;
}
}
GetImportantValue多态性=(myClass)=>myClass.GetImportantValue();
测试=()=>{
var交互计数=10000000;
var t0=performance.now();
对于(变量i=0;i
据我所知,第一个示例有一个动态/虚拟运行时调用
myClass.GetImportantValue()
,就是这样。但是第二个也有一个动态/虚拟运行时调用
myClassEnum.type
,然后检查开关中的条件

很可能代码中有一些错误,但我找不到。我认为唯一能影响结果的是
性能。now()
。但我认为这不会有太大影响。

我看不出你的脚本中有“错误”。虽然我真的不鼓励以这种方式进行性能测试,但根据我的直觉,我仍然可以说几句话。我对控制组等没有可靠的、经过良好测试的结果,所以我所说的一切都要小心谨慎

现在,对我来说,假设第一个选项会吃掉第二个选项的灰尘是很正常的,因为在js中有两件事情比变量访问更昂贵:

  • 对象属性访问(可能是O(1)哈希表,但仍然比变量访问慢)
  • 函数调用
如果我们计算函数调用和对象访问:

  • 第一种情况:5次调用[to
    GetImportantValue
    ]x(1次对象访问[to
    myClass
    ]+1次函数调用[to
    GetImportantValue
    ]===>总共10次函数调用+5次对象访问
  • 第二种情况:5次调用[to
    getImportantValueSwitch
    ]+5次对象访问[to
    MyClassEnum
    ]===>总共5次函数调用+5次对象访问
还有一件事需要提及,在第一种情况下,您有一个调用另一个函数的函数,因此您最终会得到一个范围链。这种情况的净影响很小,但在性能方面仍然是有害的

如果我们考虑到以上所有因素,第一个会慢一点。但是会慢多少?这不容易回答,因为这取决于供应商的实现,但在您的情况下,chrome会慢25倍左右。假设我们在第一个情况下有两倍的函数调用和一个范围链,我们预计会慢2到3倍,但not 25

我认为,性能的指数级下降是由于事件循环的饥饿造成的,这意味着当你给js一个同步任务时,由于它是单线程的,如果任务很麻烦,那么事件循环就无法继续,并且会停滞一秒钟左右。当人们看到setTimeout或其他异步调用在远离目标时间帧时的奇怪行为。正如我所说的,这是因为之前的同步任务花费的时间太长。在您的例子中,您有一个重复1000万次的同步for循环

为了验证我的假设,将
迭代计数减少到100000,即减少100倍,您将看到在chrome中,比率将从~20减少到~2。因此,底线1:您观察到的部分低效率来自于您正在饥饿事件循环的事实,但它仍然没有改变第一个选项的事实速度较慢

要测试函数调用是否确实是此处的瓶颈,请将脚本的相关部分更改为:

class1 = class1.GetImportantValue;
class2 = class2.GetImportantValue;
class3 = class3.GetImportantValue;
class4 = class4.GetImportantValue;
class5 = class5.GetImportantValue;
对于测试:

for (var i = 0; i < INTERATION_COUNT; i++) {
        class1();
        class2();
        class3();
        class4();
        class5();
    }
for(变量i=0;i
产生的小提琴:


这一次你会看到第一个更快,因为它是(5个函数调用)与(5个函数调用+5个对象访问)。

V8开发者在这里。你的直觉是正确的:这个微基准不是很有用

一个问题是,所有的“类”都具有相同的形状,因此“多态”情况实际上是单态的(如果您解决了这个问题,请注意V8在=5个多态情况下具有截然不同的性能特征!)

一个问题是您依赖于堆栈替换(
for (var i = 0; i < INTERATION_COUNT; i++) {
        class1();
        class2();
        class3();
        class4();
        class5();
    }