ColdFusion 2016性能与ColdFusion 9的对比

11
我们正在升级从ColdFusion 9到ColdFusion 2016,并且我们已经注意到整体性能下降。我们运行了几个模拟来提供更多的见解。以下是一个脚本,它给出了性能下降的一个很好的例子。该脚本构建查询,然后从查询创建结构。
<!--- Machine info --->
<cfset runtime = createObject("java", "java.lang.System")>
<cfset props = runtime.getProperties()> 
<cfset env = runtime.getenv()> 

<Cfoutput>

coldfusion: #SERVER.ColdFusion.ProductVersion# #SERVER.ColdFusion.ProductLevel#<br>

java.version: #props["java.version"]#<br>
java.vm.name: #props["java.vm.name"]#<br>
os.name: #props["os.name"]#<br>

PROCESSOR_IDENTIFIER: #env["PROCESSOR_IDENTIFIER"]#<br>
PROCESSOR_ARCHITECTURE: #env["PROCESSOR_ARCHITECTURE"]#<br>
NUMBER_OF_PROCESSORS: #env["NUMBER_OF_PROCESSORS"]#<br><Br>
</Cfoutput>

<!--- Create a query --->
<cfset myQuery = QueryNew("Name, Time, Advanced", "VarChar, Time, Bit")> 
<cfset testQuery = QueryNew("ColumnA,ColumnB,ColumnC,ColumnD,ColumnE,ColumnF,ColumnG,ColumnH,ColumnI,ColumnJ,ColumnK,ColumnL,ColumnM,ColumnN","VarChar,VarChar,VarChar,VarChar,VarChar,VarChar,VarChar,VarChar,VarChar,VarChar,VarChar,VarChar,VarChar,VarChar")>

<!--- Populate the query --->
<Cfloop from=1 to=300 index="x">
    <cfset QueryAddRow(testQuery, 1)> 
    <cfloop index="intLetter" from="#Asc('A')#" to="#Asc('N')#" step="1">
        <cfset temp = QuerySetCell(testQuery, "Column#chr(intLetter)#", "Row #x# column #intLetter#", x)> 
    </cfloop>
</cfloop>

<Cfset init = GetTickCount()>
<!--- Query to structure --->
<Cfset queryToStruct = structNEw()>
<cfloop query="testQuery">
<Cfset init2 = GetTickCount()>
    <cfset queryToStruct[testQuery.currentrow] = structNew()>
    <cfset queryToStruct[testQuery.currentrow]['ColumnA'] = structNew()>
    <cfloop list="#testQuery.columnList#" index="key">
        <cfset queryToStruct[testQuery.currentrow]['ColumnA'][testQuery[key][testQuery.currentrow]] = testQuery[key][testQuery.currentrow]>
    </cfloop>
    <cfoutput>#x#:#GetTickCount()-init2#<br></cfoutput>
</cfloop>

<cfoutput>-----------<br><b>#GetTickCount()-init#</b><br><br><Br></cfoutput>

<!---Cfdump var=#queryToStruct# --->

我们有两台完全相同硬件配置的服务器。一台运行在Windows 2008 / ColdFusion Server 9 Enterprise (Java版本1.6.0_14),另一台运行在Windows 2016 / ColdFusion 2016 Standard (Java版本1.8.0_112)上。这两台ColdFusion服务器都有相同的最小JVM堆大小(5024 MB)和最大JVM堆大小(5048 MB)。
ColdFusion 9服务器的性能比ColdFusion 2016快4倍以上。可以有人给出为什么会发生这种情况以及如何解决?
更新为了排除其他可能导致ColdFusion变慢的进程,我在同一台虚拟机上安装了ColdFusion 9、ColdFusion 11和ColdFusion 2016,同时使用内置Web服务器。默认安装设置。结果是:ColdFusion 9是最快的,其次是ColdFusion 11。ColdFusion 2016要慢得多。
更新2 改进了脚本,使其更清晰地表明该脚本正在做什么。

更新3 可以在以下网址查看结果: http://136.144.177.152/test2.asphttp://136.144.177.152/test-toma.asphttp://136.144.177.152/test-ag.asp 请注意,代码实际上是经过处理的,因此每次加载页面时结果会略有不同。

另外,我想指出我并不试图优化这段代码。我尝试制作了一个非常简单的可重现示例。唯一目的是指出性能差异,并找到原因和解决方案。

更新4 进行了一些额外的测试,并发现了潜在的问题。出于某种原因,以下代码在ColdFusion 2016 / Windows 2016上非常缓慢:

<cfset tmp = testQuery['ColumnA'][testQuery.currentrow]>

我发现很奇怪的是更新查询值并不慢。例如:

<cfset testQuery['ColumnA'][testQuery.currentrow] = key>

所有结果可以在这里找到:http://136.144.177.152/test5.asphttp://136.144.177.152/test6.asp。我还在我的笔记本电脑上安装了coldfusion 2016,并没有发现性能问题。我还尝试在Windows 2012机器上安装coldfusion 2016。在这里,我发现了相同的性能问题。
第五次更新: 根据Tomalak的建议,我删除了索引访问符号。这显然是coldfusion 2016的性能问题。实际结果可以在这里找到http://136.144.177.152/bug-adobe.asp。我在adobe开了一个问题报告https://tracker.adobe.com/#/view/CF-4201966

ColdFusion 2009不是一个版本。你的意思是ColdFusion 9吗? - Miguel-F
3
请先删除Evaluate()调用。 - Tomalak
@Miguel-F 是的,抱歉我想说的是 ColdFusion 9。 - Nebu
@Tomalak已删除了evaluate函数。 - Nebu
@Ageax 没有任何更改。 - Nebu
显示剩余15条评论
3个回答

3

我真的无法复现这个问题。在我使用的ColdFusion 2016上运行得非常快。我已经创建了一个优化版本的QueryToStruct代码,但除此之外几乎没有区别。

我没有可用的CF 9服务器,当您测试它时,这段代码在CF 9上是否也快4倍?

<!--- Machine info --->
<cfset runtime = createObject("java", "java.lang.System")>
<cfset props = runtime.getProperties()>
<cfset env = runtime.getenv()>
<cfoutput>
ColdFusion: #SERVER.ColdFusion.ProductVersion# #SERVER.ColdFusion.ProductLevel#<br>
java.version: #props["java.version"]#<br>
java.vm.name: #props["java.vm.name"]#<br>
os.name: #props["os.name"]#<br>
PROCESSOR_IDENTIFIER: #env["PROCESSOR_IDENTIFIER"]#<br>
PROCESSOR_ARCHITECTURE: #env["PROCESSOR_ARCHITECTURE"]#<br>
NUMBER_OF_PROCESSORS: #env["NUMBER_OF_PROCESSORS"]#<br>
<br>
</cfoutput>

<!--- Create a query --->
<cfset ROWNUM = 2000>
<cfset testColumns = "ColumnA,ColumnB,ColumnC,ColumnD,ColumnE,ColumnF,ColumnG,ColumnH,ColumnI,ColumnJ,ColumnK,ColumnL,ColumnM,ColumnN">
<cfset testTypes = "VarChar,VarChar,VarChar,VarChar,VarChar,VarChar,VarChar ,VarChar,VarChar,VarChar,VarChar,VarChar,VarChar,VarChar">
<cfset testQuery = QueryNew(testColumns, testTypes)>

<!--- Populate the query --->
<cfloop from="1" to="#ROWNUM#" index="x">
    <cfset QueryAddRow(testQuery, 1)>
    <cfloop from="#Asc('A')#" to="#Asc('N')#" index="intLetter">
        <cfset QuerySetCell(testQuery, "Column#chr(intLetter)#", "#x#-#intLetter#", x)>
    </cfloop>
</cfloop>

<!--- Convert the query to a struct --->
<cfset init = GetTickCount()>
<cfset converted = QueryToStruct(testQuery, "ColumnA")>

<cfoutput>
<b>My version:</b> #StructCount(converted)# rows, #GetTickCount()-init# ms<br>
</cfoutput>

<!--- Convert the query to a struct --->
<cfset init = GetTickCount()>
<cfset converted = QueryToStructOP(testQuery)>

<cfoutput>
<b>OP version:</b> #StructCount(converted)# rows, #GetTickCount()-init# ms<br>
</cfoutput>

<!--- +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --->
<cffunction name="QueryToStruct">
  <cfargument name="Query" type="query" required="yes">
  <cfargument name="IndexColumn" type="string" required="yes">

  <cfset var result = StructNew()>
  <cfset var rowTemplate = StructNew()>
  <cfset var key = "">
  <cfset var thisRow = "">

  <cfloop list="#Query.ColumnList#" index="key">
    <cfset rowTemplate[key] = "">
  </cfloop>

  <cfloop query="Query">
    <cfset thisRow = Duplicate(rowTemplate)>
    <cfset result[Query[IndexColumn][Query.CurrentRow]] = thisRow>
    <cfloop collection="#thisRow#" item="key">
      <cfset thisRow[key] = Query[key][Query.CurrentRow]>
    </cfloop>
  </cfloop>

  <cfreturn result>
</cffunction>

<cffunction name="QueryToStructOP">
  <cfargument name="Query" type="query" required="yes">

  <cfset var queryToStruct = StructNew()>
  <cfset var key = "">
  <cfset var index = "">

  <cfloop query="Query">
    <cfset index = Query['ColumnA'][Query.CurrentRow]>
    <cfset queryToStruct[index] = StructNew()>
    <cfloop list="#Query.ColumnList#" index="key">
      <cfset queryToStruct[index][Query[key][Query.CurrentRow]] = Query[key][Query.CurrentRow]>
    </cfloop>
  </cfloop>

  <cfreturn queryToStruct>
</cffunction>

结果(这甚至不是服务器硬件,而且还是旧的CPU):

Java版本:1.8.0_162
Java虚拟机名称:Java HotSpot(TM) 64位服务器虚拟机
操作系统名称:Windows 7
ColdFusion版本:2016,0,05,308055 Developer
处理器标识符:Intel64 Family 6 Model 42 Stepping 7, GenuineIntel
处理器架构:AMD64
处理器数量:4
我的版本:2000行,78毫秒 OP版本:2000行,229毫秒

1
评论不适合长时间讨论; 这个对话已经被移动到聊天室(https://chat.stackoverflow.com/rooms/168881/discussion-on-answer-by-tomalak-coldfusion-2016-performance-versus-coldfusion-9)。 - Samuel Liew

2

首先,你在比较CF 9企业版和CF 2016标准版。对于这个例子来说可能不是什么大问题,但如果你在标准版上进行整个应用程序的回归测试,你会看到问题。我的前任公司从9企业版迁移到2016企业版,我们看到了全面的性能提升。当你看到瓶颈时,你应该考虑重构。这也是为什么要升级的原因之一。

最大的问题在于你如何将query转换为struct。CF 2016有更先进的功能。将你的传统过程与利用查询对象中的成员函数的过程进行比较。

public array function arrayOfStructs(required query data) {
    var results = [];
    arguments.data.each(function(row) {
        arrayAppend(results, arguments.row);
    });
    return results;
}
query 成员函数 each() 将每个 row 的内容作为一个 struct 引用。无需循环遍历每一列,输入新的键并赋值。完成!非常快速。

升级吧。 :)


1
成员函数确实是语法糖,我不认为它们的性能比编译的CFML有显著提高。这两种方法应该会编译成几乎相同的Java代码。 - Tomalak
1
查询成员函数 each() 引用每一行的内容作为一个结构体,这是一个很好的抽象,但内部实际上 .each() 使用循环来构建结构体。你不必自己编写循环,但事实上它并没有消失。 ;) - Tomalak
虽然你可能是对的,我的代码可以针对ColdFusion 2016进行优化。但这并不是我的问题或意图(顺便说一下,我很感激你的贡献)。我的问题是为什么ColdFusion 2016在运行此代码时比ColdFusion 2011或ColdFusion 9慢得多。我试图制作一个非常简单的可重现的示例。 - Nebu
Adrian,你在Windows 2016或其他操作系统上运行CF 2016吗? - Nebu
@Nebu 当我们升级到CF 2016时,我们移动到了新的服务器并使用了最新的Windows服务器、JDK等。 - Adrian J. Moreno

1
我希望可以提出一个更加彻底、更容易实施的建议来解决性能和升级问题,最好是从时间和经济角度考虑:只需安装并尝试 Lucee,这是 Adobe Coldfusion 的免费、极具性能的替代品。我们在公司使用 Lucee 的多个实例来运行一个高流量的 Web 应用程序,该应用程序涉及统计领域的大量计算,并且我们非常满意。Lucee 是开源和社区驱动的:https://www.lucee.org/。请注意,保留了 HTML 标签,不做任何解释。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接