Неэффективно ли использовать неявное создание массива (сокращенное или буквенное обозначение) в циклах или параметрах функций?
(Это своего рода продолжение моего предыдущего вопроса о структурах)
Будет ли это:
<cfset myArray = ArrayNew(1)>
<cfloop query="myQuery">
<cfset myArray[1] = queryCol1>
<cfset myArray[2] = queryCol2>
<cfset myArray[3] = queryCol3>
<cfset funcionWithArrayParam(myArray)>
</cfloop>
... использовать системные ресурсы более эффективно, чем это:
<cfloop query="myQuery">
<cfset functionWithArrayParam([queryCol1, queryCol2, queryCol3])>
</cfloop>
?
И чтобы сохранить фокус, предположим, что массив в первом примере не служит никакой другой цели, кроме подачи функции. Кроме того, предположим, что данные запроса и / или столбца достаточно велики, чтобы сделать целесообразным рассмотрение эффективности.
Второй метод заманчив из-за его компактности, но меня беспокоит то, что я не уверен, сколько новых массивов он создает на каждой итерации. Первый метод создает один, я полагаю, из-за того, что массивы передаются по значению в CF. Но значит ли это, что второй метод создает два массива (неявно созданный и его копию для использования в функции)?
Также было бы интересно узнать, как сокращенная запись сравнивает по производительности несколько операторов cfset для заполнения массива. Я понимаю, что это не яблоки с яблоками, так как первый также создает массив, но все же... Я полагаю, я мог бы легко проверить это сам.
3 ответа
Адам Кэмерон технически ответил на мой вопрос в одном из своих комментариев, но, поскольку это не был его "официальный" ответ, я приведу свой (вместе с небольшой перспективой).
Ответ: ДА. Фактически, неэффективно использовать неявное создание массива способом, продемонстрированным в моем втором примере. Означает ли это, что вы не сможете сойти с рук большую часть времени? Конечно, нет! Но я представил два метода выполнения одной и той же операции, второй из которых вдвое менее эффективен по сравнению с первым с точки зрения использования памяти (и даже чуть-чуть медленнее)- в моем мире об этом стоит знать! Если вы по-прежнему будете настаивать на использовании неявного создания массива в такой ситуации, не помешает спросить себя, почему. Это потому, что вы думаете, что сжатие кода в одну строку впечатляет девушек-программистов? Я думаю, это что-то. "Читаемость" кажется наиболее популярным оправданием (в конце концов, это единственная мера, по которой неявное создание массива / структуры объективно не уступает явному). Если, как и я, вы находите читабельность неоднозначной, движущейся цель, нет ничего плохого в том, чтобы позволить эффективности влиять на то, как вы кодируете. Если вы знаете, как написать эффективный алгоритм, не позволяйте популярной гиперболе с "преждевременной оптимизацией" напугать вас до написания неэффективного алгоритма. Это демонстрирует отсутствие перспективы так же, как преждевременная оптимизация.
С точки зрения производительности разница будет незначительной, но неявное создание, как правило, немного медленнее, но неявное создание гораздо более читабельно, что более важно в долгосрочной перспективе, если только вы не столкнулись с какой-то проблемой масштабирования.
Изменить: Написал быстрый тестовый скрипт, и я получаю совершенно разные результаты. Я бы сказал, что оба настолько близки, что это не должно иметь значения, но запустите тест на вашей системе. Я использую это на Macbook Pro с CF10, это может варьироваться в зависимости от вашей конкретной реализации. Возможно, полученный вывод Java-байта может выявить какие-либо структурные различия между этими двумя методами.
<cfset iterations = 1000000>
<cfset start = getTickCount()>
<cfloop from="1" to="#iterations#" index="x">
<cfset a[x] = arrayNew(1)>
<cfset a[x][1] = x>
<cfset a[x][2] = x>
<cfset a[x][3] = x>
</cfloop>
<cfoutput>Explicit Array took: #getTickCount()-start#ms</cfoutput><br>
<cfset start = getTickCount()>
<cfloop from="1" to="#iterations#" index="y">
<cfset b[y] = [y, y, y]>
</cfloop>
<cfoutput>Implicit Array took: #getTickCount()-start#ms</cfoutput><br>
Спектакль? Не беспокойся об этом. Любой тест, в котором вам необходимо выполнить петлевую петлю, чтобы увеличить продолжительность тестируемой операции, чтобы указанная продолжительность была измеряемой, по сути, демонстрирует, что соображения производительности незначительны.
Что касается того, сколько массивов создается? В каждом примере в вызывающем коде создается один массив, затем он в основном дублируется при передаче в функцию. Так что никакой реальной разницы нет.
Все сводится к тому, что вы считаете более понятным (мы, вероятно, закорачиваем последующие вопросы, которые могут у вас возникнуть, указав, что это всегда будет ответом).
Лично я думаю, что иметь отдельные операторы для установки каждого элемента массива немного неуклюже, когда можно сделать это одним ударом.