【问题标题】:ColdFusion 2016 performance versus ColdFusion 9ColdFusion 2016 与 ColdFusion 9 的性能对比
【发布时间】:2018-09-21 02:38:48
【问题描述】:

我们正在从 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 服务器的性能提高了 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。在这里我发现了同样的性能问题。

更新 5 根据 Tomalak 的建议,我删除了索引访问表示法。这显然是 Coldfusion 2016 的性能问题。实际结果可以在这里找到http://136.144.177.152/bug-adobe.asp。我在 adobe 上为这个问题打开了一个错误 https://tracker.adobe.com/#/view/CF-4201966

【问题讨论】:

  • ColdFusion 2009 不是一个版本。你是说 ColdFusion 9 吗?
  • 第一步,请摆脱Evaluate() 电话。
  • @Miguel-F 是的,抱歉我的意思是coldfusion 9
  • @Tomalak 删除了评估功能。
  • @Nebu - 结果有什么变化吗?

标签: coldfusion coldfusion-2016


【解决方案1】:

我无法重现问题,真的。这在我的 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.version: 1.8.0_162 java.vm.name:Java HotSpot(TM) 64 位服务器虚拟机 操作系统名称:Windows 7 ColdFusion:2016,0,05,308055 开发者 PROCESSOR_IDENTIFIER: Intel64 Family 6 Model 42 Stepping 7, GenuineIntel PROCESSOR_ARCHITECTURE:AMD64 NUMBER_OF_PROCESSORS:4 我的版本:2000 行,78 毫秒 OP 版本:2000 行,229 毫秒

【讨论】:

【解决方案2】:

首先,您将 CF 9 Enterprise 与 CF 2016 Standard 进行比较。对于这个例子来说应该没什么大不了的,但是如果你在 Standard 上对整个应用程序进行回归测试,你会发现问题。我以前的公司从 9 Ent 迁移到 2016 Ent,我们看到的只是全面的绩效改进。当您看到瓶颈时,您应该始终考虑重构。这是您升级的原因之一。

最大的问题是如何将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 引用。无需遍历每一列,输入一个新键并分配一个值。繁荣!完毕。快得要命。

进行升级。 :)

【讨论】:

  • 成员函数确实是语法糖,我不希望它们的性能明显优于编译的 CFML。两种方法都应该编译成或多或少相同的 Java 代码。
  • 例如:"查询成员函数each() 引用每个row 的内容作为struct。" 这是一个很好的抽象,但在内部,@ 987654331@ 使用循环来构建结构。您不必自己编写循环这一事实并不会使其消失。 ;)
  • 虽然你可能是对的,我的代码可以针对coldfusion 2016进行优化。这不是我的问题,也不是我的意图(顺便说一句,我很感谢你的贡献)。我的问题是为什么coldfusion 2016 运行此代码比coldfusion 2011 或coldfusion 9 慢得多。我试图制作一个非常简单的可重现示例。
  • Adrian 您是在 Windows 2016 还是其他操作系统上运行 CF 2016?
  • @Nebu 当我们升级到 CF 2016 时,我们迁移到带有最新 Windows 服务器、JDK 等的新服务器。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-13
  • 1970-01-01
  • 1970-01-01
  • 2020-05-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多