Производительность 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/