2012-11-11 40 views
0

从数据库我加载约1000行。为什么调用很多匿名函数太慢?

我有一个打印表的类。鉴于我定义一些规则,几乎对每一列,例如:

<% table.rules :date_uzp, lambda { |row| l row.date_uzp if row.date_uzp.present? } %> 
<% table.rules :another_column, lambda { |row| helper_method row } %> 

而在最后,只需要调用<%= table.print%>,它为表生成HTML。

为什么我需要一个特殊的类来生成表?表格在这个项目中是非常具体的,所以遵循DRY的原则,我有类。

但是有一个问题,如果我处理几乎所有的列和调用匿名函数,它是如此之慢。 (匿名功能被称为大约10 000次,我知道,这是相当多的,但它不能这么慢)页面正在加载大约50秒。

问题在哪里?你有什么建议?

+0

你有没有把它命名?你为什么确定它是关于lambda表达式的,而不是关于内部的代码或你的类正在做什么? – Anton

+0

当我对调用lambdas发表评论时,它会将页面加载时间从50秒减少到2秒。 –

+0

但你为什么认为这是'lambda'而不是本地化,'date_uzp'调用(这是两次BTW),'helper_method',甚至是ERB? –

回答

0

匿名函数在这里并不慢。这绝对是该功能的内容缓慢。

我最喜欢的分析工具是ruby-prof,MiniProfiler,并把内置的Benchmark.measure

初步猜测是:

  • 为O运行(N)时间昂贵的操作,因为这是真正容易得到操纵表时
  • 日期解析到。我的经验是,一些日期解析功能是快速的,而另一些可能是狗慢(注意到使用date_uzp;不确定具体,只是指出它的可能性)。
  • 加载1000点的对象,那么加载多个关联(尤指具有多)每个对象上。加载多个activerecord对象可能非常慢,特别是如果它增加堆大小/开始触发大量垃圾回收。

编辑

好吧,另外一种想法。 Lambdas(以及红宝石中的所有块)创建关闭以保持其上下文。也许你的lambdas的策略是防止大量的对象被垃圾收集?不过,我不确定如何通知您重构代码。我知道如何在不关闭创建拉姆达的唯一方法是这样的:

def foo 
    lambda {|row| helper_method row} 
end 

但一定是一个更好的方式来组织代码。

+0

当我将lambda的内容更改为{| row | },它仍然需要11秒加载。有什么不同必须是错的...... –

+0

好吧,又有一个想法(见答案编辑) – Woahdae