调用组件函数与内联代码时的开销-ColdFusion



我一直在诊断生成一个包含约50000行的CSV的性能问题,并将其缩小到每行使用一次的单个函数。

经过一番折腾,我发现使用函数而不是将逻辑直接放在循环中会有开销——我的问题是:为什么?!

有问题的函数非常简单,它接受一个字符串参数,并将其传递给一个包含大约15个选项的switch/case块,返回结果字符串。我到处都放了一堆计时器,发现这个函数调用的很多(不是全部)时间都在0到200毫秒之间。。。然而,如果我把完全相同的代码放在内联中,它在每次迭代中都位于0。

所有这些都指向了我对对象实例化的理解中的一个基本问题,我希望能澄清一下。

我一直认为,如果我在页面顶部实例化一个组件,或者如果我在像Application或Session这样的持久作用域中实例化它,那么它就会被放入内存中,随后对该组件中函数的调用会非常快。然而,调用这些函数似乎有开销,虽然我们只讨论了几毫秒,但当你必须这样做50000次时,它很快就会累积起来。

此外,这样做似乎会消耗资源。我对JVM使用内存的方式不是特别熟悉,我读过它,也玩过设置之类的东西,但这是一个压倒性的话题,尤其是对于我们这些没有Java开发经验的人来说。看起来,当通过内联代码调用该方法时,有时ColdFusion服务会崩溃,请求永远不会结束。其他时候它确实完成了,尽管太慢了。这表明只有当服务器有资源处理请求时,请求才能完成,因此方法调用本身正在消耗内存。。。(?)

如果一个方法的调用确实有附加开销,那么我就有一个大问题了。将所有这些代码都内联是不可行的(虽然有问题的函数很简单,但我还需要使用很多其他函数),这样做违背了我作为开发人员的所有信念!!

因此,如有任何帮助,我们将不胜感激。

为了清楚起见,因为我相信有人会要求它,下面是有问题的代码:

编辑:根据建议,我已经将代码更改为使用结构查找,而不是CFSwitch-下面是修改后的代码以供参考,但底部的pastebin链接中也有一个测试应用程序。

init方法内部:

    <cfset  Variables.VehicleCategories = {
            'T1'    : 'Beetle'
        ,   'T1C'   : 'Beetle Cabrio'
        ,   'T2'    : 'Type 2 Split'
        ,   'T2B'   : 'Type 2 Bay'
        ,   'T25'   : 'Type 25'
        ,   'Ghia'  : 'Karmann Ghia'
        ,   'T3'    : 'Type 3'
        ,   'G1'    : 'MK1 Golf'
        ,   'G1C'   : 'MK1 Golf Cabriolet'
        ,   'CADDY' : 'MK1 Caddy'
        ,   'G2'    : 'MK2 Golf'
        ,   'SC1'   : 'MK1/2 Scirocco'
        ,   'T4'    : 'T4'
        ,   'CO'    : 'Corrado'
        ,   'MISC'  : 'MISC'
    } />

正在调用的函数:

<cffunction name="getCategory" returntype="string" output="false">
    <cfargument name="vehicleID" required="true" type="string" hint="Vehicle type" />
    <cfscript>
        if (structKeyExists(Variables.VehicleCategories, Arguments.VehicleID)) {
            return Variables.VehicleCategories[Arguments.VehicleID];
        }
        else {
            return 'Base SKUs';
        }
    </cfscript>
</cffunction>

根据请求,我创建了一个测试应用程序来复制这个问题:

http://pastebin.com/KE2kUwEf-应用.cfc

http://pastebin.com/X8ZjL7D7-TestCom.cfc(放在webroot外部的"com"文件夹中)

http://pastebin.com/n8hBLrfd-index.cfm

在任何语言中,函数调用总是比内联代码慢。这就是为什么C++中有inline关键字,JVM中有JIT优化器,如果它认为有必要,它会为您内联函数。

现在ColdFusion是JVM之上的又一层。因此,CF中的函数不是JVM中的函数,所以从JIT优化器的角度来看,事情不会1:1转换。CFML函数实际上被编译为Java类。此外,每次调用都会创建argumentslocal(Java哈希表)等作用域。这需要时间和内存,因此也需要开销。

如果我在像Application或会话,然后将其放入内存,并随后调用该组件内的功能将是闪电般快速的

它肯定比实例化一个新实例快,但不会"闪电般快",尤其是当你在一个紧密的循环中调用它时。

总之,内联函数,如果它仍然不够快,请找到代码中最慢的部分并用Java编写。

这里只需要补充一点,因为Railo使用内部类而不是完整的独立类,所以如果您以这样一种风格编写,即具有许多小函数,则会更快。在我的实验中,两个引擎在使用基本的内联代码时表现相似。如果您需要在负载下提高性能,Adobe ColdFusion可以提供大型神函数。由于JVM在编译过程中无法内联ColdFusion函数,您将永远无法从编译器对代码的智能化中获益。

如果您创建了一个使用大量显式getter/setter的应用程序,并且发现流量从小容量增加到大容量,那么这一点尤为重要。所有这些小功能都会让你屈服,而不是拥有更少的大型"上帝"功能。

我们进行了100000次迭代的一个基本测试,从最慢到最快:

Adobe ColdFusion(许多小功能)(比Java慢200X)Railo(许多小功能)(速度慢60X)ColdFusion/Railo(所有代码都在一个巨大的函数中内联)(慢10倍)本机Java类(最快)

相关内容

  • 没有找到相关文章

最新更新