3

我在 Rails 应用程序中有一个花哨的“工作表”样式视图,加载时间太长。(在开发模式下,是的,我知道那里没有缓存,“在 57893 毫秒内完成(查看:54975,DB:855)”)工作表是使用辅助方法呈现的,因为我无法忍受为工作表中不同类型的行。现在我想知道 partials 是否真的会更快?

我已经分析了页面加载并确定了一些对象缓存将减少几秒钟的情况,但配置文件输出表明大量时间用于简单地循环通过 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.breakpointsystems.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 中实现了它们. (干燥且可单元测试。)Javascript 仅用于编辑视图,仅用于添加/删除行(仅限客户端)并在单元格内容更改时获取包含新总数的工作表。它获取整个表格,因为当输入单元格更改时,将近一半的值会更新。

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

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

4

2 回答 2

7

我最终在http://www.infoq.com/articles/Rails-Performance阅读了一篇出色的文章(“A Look At Common Performance Problems In Rails”)。然后我按照作者的建议在请求处理期间缓存计算:

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

因为我的工作表一遍又一遍地执行上述操作,然后在这些结果的基础上计算更多行,这导致了90%的加速。本来应该平淡无奇的,但一开始只有几个总数,然后我向客户展示了原型,它从那里滚雪球:)

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

最后,我放置了一些对象缓存。数据库中的“幻数”一年最多只变化几次,其中一些是加密的,但在大部分计算中都需要用到。这是缓存的成熟果实,它又缩短了 1.25 秒。

接下来我将查看关联的急切加载,因为可能有一些时间可以保存在那里,我将按照@tadman 的建议对发送“仅数据”与发送 HTML 进行快速比较。关于我可以缓存的唯一部分是导航侧边栏。所有其他内容取决于请求参数。

感谢您的建议!

于 2010-08-10T18:45:13.597 回答
4

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

尽管帮助方法比部分方法更快,而且直接的字符串插值更快,但很难说由此带来的性能提升是否值得追求。在开发环境中,渲染大量的局部可能是一个瓶颈,但在生产环境中,它们的影响似乎不那么严重。

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

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

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

于 2010-08-06T18:07:04.780 回答