助手真的比部分快吗?字符串构建怎么样?

时间:2010-08-06 17:38:01

标签: ruby-on-rails performance string helpers partials

我在Rails应用程序中有一个花哨的“工作表”样式视图,需要花费太长时间才能加载。 (在开发模式下,是的,我知道那里没有缓存,“在57893ms完成(查看:54975,数据库: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使用partials意味着打开文件,分离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/

@tadman: 有行总计和列总计(以及更多的柱状算术),因为它们不仅仅是总数,而且还依赖于数据库中的其他“幻数”,我在Ruby代码而不是Javascript中实现它们。 (DRY和单元可测试。)Javascript仅在编辑视图中使用,仅用于添加/删除行(仅限客户端),并在单元格内容更改时获取具有新总计的工作表。它获取整个表,因为当输入单元格发生变化时,将近一半的值会更新。

工作表及其行实际上是虚拟模型;它们并不存在于数据库中,而是汇集了大量真正的AR对象。每次视图呈现时都会创建它们(但在开发模式下需要1.7秒,所以我并不担心它。)

我想我可以传输一个数字矩阵,而不是标记内容,并让JS将其解压缩到工作表中。但这很快就无法维持。

2 个答案:

答案 0 :(得分:7)

我最后在http://www.infoq.com/articles/Rails-Performance阅读了一篇优秀的文章(“看看Rails中的常见性能问题”)。然后我按照作者的建议在请求处理期间缓存计算:

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

因为我的工作表反复执行上述内容,然后在这些结果的基础上计算更多行,这导致了 90%加速。本来应该很简单,但它只是从几个总数开始,然后我向客户展示了原型,并从那里滚雪球:)

我也想知道我的基于数组的数学是否效率低下,所以我用NArray(http://narray.rubyforge.org/)替换了Ruby数组。加速可以忽略不计,但代码更干净,所以它就是这样。

最后,我将一些对象缓存放在适当的位置。数据库中的“幻数”最多每年只更改几次,其中一些是加密的,但它们需要在大多数计算中使用。这是缓慢成熟的缓存水果,它再削减了1.25秒。

我接下来会看到热切的关联加载,因为可能有一些时间来保存,我会快速比较发送“只是数据”与发送HTML,正如@tadman建议的那样。关于我可以缓存的唯一部分是导航侧边栏。所有其他内容都取决于请求参数。

感谢您的建议!

答案 1 :(得分:4)

在内部,所有部分都被转换为可执行Ruby代码块,并且运行与任何帮助器方法完全相同的运行时。当格式错误的模板导致生成的代码无法编译时,您可以定期看到这一点。

虽然有理由说辅助方法比部分方法更快,并且直接的字符串插值仍然更快,但很难说这样做的性能增益是否值得追求。在登录开发环境方面,渲染大量的部分可能是瓶颈,但在生产环境中,它们的影响似乎不那么严重。

解决这个问题的唯一方法是使用两种不同的渲染方法对页面进行基准测试。

正如您所指出的,缓存是您获得巨大收益的地方。使用Memcached来保存大量预渲染的HTML内容可以使您的加载时间呈指数级增长。将10,000行呈现到HTML中总是比从Rails.cache子系统中检索相同的代码段慢。

同样的情况是,您不呈现的内容始终呈现最快,因此您可以采取的任何措施来减少为每个帮助程序调用生成的内容量将带来巨大收益。如果您正在构建一个完全依赖于JavaScript的大型电子表样式应用程序,您可能会发现将数据捆绑为JSON数组并在客户端扩展它比在服务器上展开HTML并将其发送出去要快得多那样。