Производительность ColdFusion 2016 по сравнению с ColdFusion 9

Мы находимся в процессе обновления с 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 МБ) и максимальный размер кучи JVM (5048 МБ).

Производительность сервера ColdFusion 9 более чем в 4 раза выше. Может кто-нибудь дать объяснение, почему это происходит и как это решить?

Обновить

Чтобы исключить любой другой процесс, который мог бы замедлить работу ColdFusion, я установил ColdFusion 9, ColdFusion 11 и ColdFusion 2016 на одну виртуальную машину и использовал встроенный веб-сервер. Настройки по умолчанию. Результат: ColdFusion 9 - самый быстрый, за ним следует ColdFusion 11. ColdFusion 2016 намного медленнее.

Обновление 2 Внесены некоторые изменения в сценарий, чтобы было более понятно, что делает этот сценарий.

Обновление 3 Результаты можно просмотреть здесь: http://136.144.177.152/test2.asp или http://136.144.177.152/test-toma.asp или http://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.asp или http://136.144.177.152/test6.asp. Я также установил Coldfusion 2016 на свой ноутбук и не обнаружил проблем с производительностью. Я также попытался установить Coldfusion 2016 на машине Windows 2012. Здесь я нашел те же проблемы с производительностью.

Обновление 5 На основании предложения Томалака я удалил индексированную запись доступа. Это явно проблема с производительностью на Coldfusion 2016. С реальными результатами можно ознакомиться здесь http://136.144.177.152/bug-adobe.asp. Я открыл ошибку в Adobe для этой проблемы здесь https://tracker.adobe.com/.

3 ответа

Я не могу воспроизвести проблему, правда. Это работает довольно быстро на моем ColdFusion 2016. Я создал оптимизированную версию QueryToStruct код, но кроме этого есть небольшая разница.

У меня нет доступного сервера CF 9, этот код также в 4 раза быстрее на CF 9, когда вы его тестируете?

<!--- 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>

Результат (это даже не серверное оборудование, а сверх того старый процессор):

java.version: 1.8.0_162
java.vm.name: виртуальная машина 64-разрядного сервера Java HotSpot(TM)
os.name: Windows 7
ColdFusion: 2016,0,05,308055 Разработчик
PROCESSOR_IDENTIFIER: Intel64, семейство 6, модель 42, степпинг 7, GenuineIntel
PROCESSOR_ARCHITECTURE: AMD64
NUMBER_OF_PROCESSORS: 4

Моя версия: 2000 строк, 78 мс
ОП версия: 2000 строк, 229 мс

Сначала вы сравниваете CF 9 Enterprise со стандартом CF 2016. Для этого примера это не должно иметь большого значения, но если вы регрессивно тестируете все приложение на 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, Не нужно перебирать каждый столбец, вводить новый ключ и назначать значение. Boom! Готово. Быстро, как в аду.

Сделайте свое обновление.:)

Я надеюсь, что можно дать рекомендацию, которая решает проблему производительности и обновления другим (более радикальным) способом, который в лучшем случае легче реализовать по (временным) экономическим причинам: просто установите и попробуйте Lucee, бесплатную чрезвычайно производительную альтернативу. к версии Adobe Coldfusion. Мы используем Lucee с несколькими экземплярами в нашей компании для веб-приложения с высоким трафиком в области статистики, которое требует большой вычислительной мощности, и мы очень довольны. Lucee является драйвером сообщества с открытым исходным кодом: https://www.lucee.org/

Другие вопросы по тегам