Помощники действительно быстрее, чем частичные?А как насчет построения строки? - PullRequest
3 голосов
/ 06 августа 2010

У меня есть причудливое представление стиля "рабочий лист" в приложении Rails, которое загружается слишком долго. (В режиме разработки, и да, я знаю, что там нет кэширования, «Завершено за 57893 мс (Представление: 54975, DB: 855)»). Рабочий лист отображается с использованием вспомогательных методов, потому что я не мог поддерживать множество маленьких маленьких частичек для различные виды строк на листе. Теперь мне интересно, могут ли быть частичные на самом деле быстрее?

Я профилировал загрузку страницы и выявил несколько случаев, когда кеширование объектов будет сбиваться на несколько секунд, но вывод профиля показывает, что большой кусок времени тратится на простое циклическое прохождение составляющих объектов модели Worksheet и добавление строки вывод от помощника. Вот пример того, о чем я говорю:

def header_row(wksht)
  content_tag(:thead, :class => "ioe") do
    content_tag(:tr) do
      html_row = []
      for i in (0...wksht.class::NUM_COLS) do
        html_row << content_tag(:th, h(wksht.column_headings[i].upcase),
                                :class => wksht.column_classes[i])
      end
      html_row.join("\n")
    end
  end
end

OTOH, используя партиалы, означает открывать файлы, раскручивать интерпретатор Ruby и, в конце концов, собирать кучу строк, верно? Поэтому мне интересно, есть ли другой способ ускорить работу помощников. Должен ли я использовать что-то вроде stringstream (существует ли он в Ruby?), Должен ли я избавиться от вызовов content_tag в пользу моей собственной "" интерполяции строк ... Я готов написать свои собственные тесты производительности и поделиться результаты, если у вас есть предложенные альтернативы подходу, который я уже выбрал.

Поскольку это довольно сложный вид (и также имеет редактируемую версию), я бы не стал переписывать и профилировать все это более одного раза. :)

Некоторые связанные чтения:

http://www.viget.com/extend/helpers-vs-partials-a-performance-question/ (старый)
http://www.breakingpointsystems.com/community/blog/ruby-string-processing-overhead/
http://blog.purepistos.net/index.php/2008/07/14/benchmarking-ruby-string-interpolation-concatenation-and-appending/

@ Тадман: Существуют итоговые значения по строкам и столбцам (и более по столбчатой ​​арифметике), и, поскольку они не только являются итоговыми значениями, но также зависят от других «магических чисел» из базы данных, я реализовал их в коде Ruby, а не в JavaScript. (СУХОЙ и проверяемый на единицу.) Javascript используется только в представлении редактирования, и только для добавления / удаления строк (только на стороне клиента) и для извлечения листа со свежими итогами при изменении содержимого ячейки. Он извлекает всю таблицу, потому что почти половина значений обновляется при изменении входной ячейки.

Рабочий лист и его строки на самом деле являются виртуальными моделями; они не живут в БД, а скорее объединяют множество реальных объектов AR. Они создаются каждый раз при рендеринге вида (но это занимает 1,7 секунды в режиме разработки, поэтому я не беспокоюсь об этом).

Полагаю, я мог бы передать матрицу чисел, а не размеченный контент, и заставить JS распаковать его в лист. Но это становится недостижимым быстро.

Ответы [ 2 ]

7 голосов
/ 10 августа 2010

В итоге я прочитал отличную статью на http://www.infoq.com/articles/Rails-Performance («Взгляд на общие проблемы с производительностью в Rails»). Затем я последовал предложению автора кешировать вычисления во время обработки запроса:

def estimated_costs
  @estimated_costs ||=
    begin
      # tedious vector math
    end
end

Поскольку мой рабочий лист снова и снова выполняет подобные действия, а затем использует эти результаты для вычисления еще нескольких строк, это привело к ускорению 90% сразу. Должно быть, как день, но все началось с нескольких итогов, затем я показал прототип покупателю, и оттуда он вылетел:)

Я также задавался вопросом, может ли моя математика на основе массива быть неэффективной, поэтому я заменил Ruby Array of массивов чисел на NArray (http://narray.rubyforge.org/). Ускорение было незначительным, но код стал чище, поэтому он остается таким.

Наконец, я добавил кеширование объектов. «Магические числа» в базе данных меняются не чаще, чем несколько раз в год, и некоторые из них шифруются, но их необходимо использовать в большинстве расчетов. Это низко висящий фрукт, созревший для кеширования, и он сбрил еще 1,25 секунды.

Далее я посмотрю на готовую загрузку ассоциаций, так как там, вероятно, есть время для сохранения, и я сделаю быстрое сравнение отправки «только данных» с отправкой HTML, как предложил @tadman. Единственное, что я могу кэшировать - это боковая панель навигации. Все остальное содержимое зависит от параметров запроса.

Спасибо за ваши предложения!

4 голосов
/ 06 августа 2010

Внутренне все партиалы преобразуются в блок исполняемого кода Ruby и выполняются точно так же, как и любые вспомогательные методы.Периодически вы можете увидеть проблески этого, когда неправильно сформированный шаблон приводит к тому, что сгенерированный код не может быть скомпилирован.

Хотя вполне понятно, что вспомогательные методы работают быстрее, чем партиалы, а прямая интерполяция строк еще быстрее, это сложносказать, если выигрыш в производительности от этого стоило бы преследовать.Рендеринг очень большого количества партиалов может быть узким местом с точки зрения регистрации в среде разработки, но в производственной среде их влияние кажется менее серьезным.

Единственный способ выяснить это - сравнить ваши страницыиспользуя два разных метода рендеринга.

Как вы указали, кэширование - это то, где вы получаете большие выгоды.Использование Memcached для сохранения больших фрагментов предварительно отрендеренного HTML-контента может значительно увеличить время загрузки.Рендеринг 10000 строк в HTML всегда будет медленнее, чем получение одного и того же фрагмента из подсистемы Rails.cache.

Также бывает, что контент, который вы не отображаете, всегда отображается быстрее, поэтому вы можете делать все, что угодночтобы уменьшить объем контента, который вы генерируете для каждого вызова помощника, вы получите большой выигрыш.Если вы создаете большое приложение в стиле электронных таблиц, полностью зависящее от JavaScript, вы можете обнаружить, что объединение данных в массив JSON и расширение на стороне клиента значительно быстрее, чем развертывание HTML на сервере и его пересылкатаким образом.

...