Performance 调用组件函数与内联代码时的开销-ColdFusion
我一直在诊断一个性能问题,生成一个包含大约50000行的CSV,并将其缩小为一个函数,每行使用一次 在经历了很多混乱之后,我发现在使用函数时会有开销,而不是将逻辑直接放在循环中——我的问题是:为什么 所讨论的函数非常简单,它接受一个字符串参数并将其传递给一个包含大约15个选项的开关/大小写块-返回结果字符串。 我在各处都放了一堆计时器,发现这个函数调用的大部分(不是全部)时间都在0到200毫秒之间运行。。。但是,如果我将完全相同的代码内联,则每次迭代时它都位于0 所有这些都指向了我对对象实例化理解中的一个基本问题,我希望得到一些澄清 我总是觉得,如果我在页面顶部实例化一个组件,或者如果我在一个持久作用域(如应用程序或会话)中实例化它,那么它将被放入内存中,随后对该组件中的函数的调用将是闪电般的快。 然而,调用这些函数似乎有一个开销,虽然我们只讨论了几毫秒,但当你不得不这样做50000次时,它很快就会加起来 此外,这样做似乎会消耗资源。我对JVM使用内存的方式不是特别精通,我已经阅读了JVM的相关知识,并使用了设置等,但这是一个压倒性的话题——特别是对于我们这些没有Java开发经验的人来说。当通过内联代码调用该方法时,有时ColdFusion服务会崩溃,请求永远不会结束。其他时候它确实完成了,尽管速度太慢了。这表明只有当服务器有资源处理请求时,请求才能完成——因此方法调用本身正在消耗内存。。。(?) 如果一个方法的调用确实有额外的开销,我就有一个大问题。将所有这些代码内联(虽然所讨论的函数很简单,但还有很多其他函数我需要使用)是不可行的,这样做违背了我作为开发人员所相信的一切 因此,任何帮助都将不胜感激 为了清楚起见,而且我相信有人会要求,下面是有问题的代码: 编辑:根据建议,我已将代码更改为使用结构查找而不是CFSwitch-下面是供参考的修订代码,不过底部的pastebin链接中还有一个测试应用程序 在init方法内部:Performance 调用组件函数与内联代码时的开销-ColdFusion,performance,coldfusion,jvm,components,overhead,Performance,Coldfusion,Jvm,Components,Overhead,我一直在诊断一个性能问题,生成一个包含大约50000行的CSV,并将其缩小为一个函数,每行使用一次 在经历了很多混乱之后,我发现在使用函数时会有开销,而不是将逻辑直接放在循环中——我的问题是:为什么 所讨论的函数非常简单,它接受一个字符串参数并将其传递给一个包含大约15个选项的开关/大小写块-返回结果字符串。 我在各处都放了一堆计时器,发现这个函数调用的大部分(不是全部)时间都在0到200毫秒之间运行。。。但是,如果我将完全相同的代码内联,则每次迭代时它都位于0 所有这些都指向了我对对象实例化理
<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>
正在调用的函数:
<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>
if(structKeyExists(Variables.VehicleCategories,Arguments.VehicleID)){
返回变量.VehicleCategories[Arguments.VehicleID];
}
否则{
返回“基本SKU”;
}
根据要求,我创建了一个测试应用程序来复制此问题:
-Application.cfc
-TestCom.cfc(放在webroot外部的“com”文件夹中)
-index.cfm函数调用总是比任何语言中的内联代码慢。这就是为什么C++中有“代码>内联< /COD>关键字,并且在JVM Land中有JIT优化器,它将在需要时为您内联函数。 现在ColdFusion是JVM之上的另一层。因此,CF中的函数不是JVM中的函数,所以从JIT优化器的角度来看,事情不是1:1转换的。CFML函数实际上被编译成一个Java类。此外,每次调用时都会创建诸如
参数
、本地
(Java哈希表)之类的作用域。这些需要时间和内存,因此需要开销
…如果我在应用程序或
会话,然后将其放入内存中并随后调用
该组件中的功能将是闪电般的快
当然,它比实例化一个新实例要快,但它不会“闪电般地快”,特别是当您在一个紧密的循环中调用它时
总之,内联函数,如果它仍然不够快,找到代码中最慢的部分并用Java编写。这里只是一个旁注,因为Railo使用内部类而不是完全独立的类,如果您以这样一种风格编写,从而拥有许多小函数,那么速度会更快。在我的实验中,两个引擎对基本内联代码的性能相似。如果您需要在负载下提高性能,Adobe ColdFusion可以使用大型god函数。由于JVM无法在编译过程中内联ColdFusion函数,因此您永远无法从编译器智能处理代码中获益 如果您创建了一个使用大量显式getter/setter的应用程序,并且发现流量从小流量增加到大流量,那么这一点尤为重要。所有这些小功能都会让你屈服,而大的“上帝”功能会更少 通过一个基本测试,我们运行了100000次迭代,从最慢到最快: Adobe ColdFusion(许多小函数)(比Java慢200倍) Railo(许多小功能)(速度慢60倍) ColdFusion/Railo(所有代码内联在一个巨大的函数中)(速度慢10倍)
本机Java类(最快)不确定发生了什么,但我要做的第一件事是将开关更改为结构查找。哦,确保cfcomponent和cffunction标签上有
output=false
!这将增加开销,可能会降低速度。为什么不在页面上创建一个结构并以这种方式引用它呢?我不认为函数是处理这个问题的最佳方法。而且精确的CF和JVM版本可能是相关的,因此应该提供信息。不要阅读所有最新的评论,但要快速注意:如果你有“Report Exe