2011-05-26 157 views
0

这是一个模糊的问题,我知道....但在这块代码的性能是可怕的。从原始帖子到渲染页面的动作大约需要15秒...如何加快这个Rails代码?

此操作的目的是从CV中检索所有职业,并从该CV和职业中获取所有技能。他们需要组织成两个阵列:

  • 第一个数组包含所有职业(无重复),并根据他们的分数排序。 Fo每个双重入口发现得分增加1

  • 第二个数组包含来自职业阵列和cv的所有技能。再次没有双打是允许的,但每遇到双重现有的分数增加一。

下面是执行此操作的代码块。与其他代码片段相比,它相对较大,但我希望这是可以理解的。我知道与阵列工作做到像我一样是混乱的,但这里是每个阵列的位置意味着:

  • 位置0:在实际工作技能/职业目标
  • 位置1:项的得分
  • 位置2:在db中发现的位置
  • 位置3:在CV

    发现位置的DEF归类

    @cv = Cv.find(params[:cv_id], :include => [:desired_occupations, :past_occupations, :educational_skills]) 
    @menu = :second 
    @language = Language.resolve(:code => :en, :name => :en) 
    @occupation_hashes = [] 
    @skill_hashes = [] 
    
    (@cv.desired_occupations + @cv.past_occupations).each do |occupation| 
        section = [] 
        section << 'Desired occupation' if @cv.desired_occupations.include? occupation 
        section << 'Work experience' if @cv.past_occupations.include? occupation 
    
        unless (array = @occupation_hashes.assoc(occupation)).blank? 
        array[1] += 1 
        array[2] = (array[2] & section).uniq 
        else 
        @occupation_hashes << [occupation, 1, section] 
        end 
    
        occupation.skills.each do |skill| 
        unless (array = @skill_hashes.assoc skill).blank? 
         label = occupation.concept.label(@language).value 
         array[1]+= 1 
         array[3] << label unless array[3].include? label 
        else 
         @skill_hashes << [skill, 1, [], [occupation.concept.label(@language).value]] 
        end 
        end 
    end 
    
    @cv.educational_skills.each do |skill| 
        unless (array = @skill_hashes.assoc skill).blank? 
        array[1]+= 1 
        array[3] << 'Education skills' unless array[3].include? 'Education skills' 
        else 
        @skill_hashes << [skill, 1, ['Education skills'], []] 
        end 
    end 
    
    # Sort the hashes 
    @occupation_hashes.sort! { |x,y| y[1] <=> x[1]} 
    @skill_hashes.sort! { |x,y| y[1] <=> x[1]} 
    
    @max = @skill_hashes.first[1] 
    @min = @skill_hashes.last[1] end 
    

我可以发布更多的车型和迁移,以明确每一类做什么,但我觉得上面的脚本的前几行应该是在协会明确。我正在寻找一种方法来优化每个循环...

+0

在优化速度之前,我会考虑重新组织以清晰起见。编写一个简短(最多5行)的层次结构,明确命名的方法:可能有'create'调用'rank_experience'和'rank_skills',或类似的东西。在这样做的时候,你可以解决你自己的性能问题。如果没有,您的代码仍然会更容易让其他人阅读和评论,并且更容易维护。 (“Clean Code”是关于这个主题的一本很好的书。) – 2011-05-26 14:52:44

+0

这有点单一,但回到你的问题,如果你自己回答,你会得到更好的答案。 [这是我推荐的方法。](http://stackoverflow.com/questions/4295799/how-to-improve-performance-of-this-code/4299378#4299378) – 2011-05-26 15:49:12

+0

我会先重构一下代码。 – 2011-05-26 16:29:22

回答

1

这就是那里的代码块。一般来说,如果你正在编写严肃的方法,你将来在维护它时会遇到麻烦。一种技术可以帮助分解整体代码块,并将它变成一个帮助类,以更逻辑的阶段进行处理,从而更易于微调它的各个方面。

例如,接口可能是:

@categorizer = CvCategorizer.new(params[:cv_id]) 

这将封装上述所有的,并保存到与attr_reader被宣布由访问实例变量。

使用一个工具类意味着你可以打破初始化成都提出了更明确的步骤:

def initialize(cv_id) 
    # Call a wrapper method that loads the CV 
    @cv = self.load_cv(cv_id) 

    # Perform discrete steps to re-order the imported data 
    self.organize_occupations 
    self.organize_skills 
end 

这真的很难说为什么这是只是看着它缓慢的,但我会非常支付密切关注log/development.log看看那里发生了什么。这可能是最初的负载很痛苦,但其余的方法是好的。

1

你应该做一个,但在你的代码分析,看看什么是需要大量的时间。您可以了解如何处理分析器,或者只是在代码中使用时间戳在代码中添加一些简单的putslogger.info语句。可能最容易通过使用Benchmark来做到这一点。注意:您可能需要require 'benchmark' ...不确定它是否在Rails中是自动需要的。定时更大代码块

logger.info Benchmark.measure { @cv = Cv.find(params[:cv_id], :include => [:desired_occupations, :past_occupations, :educational_skills]) } 

而且:

对于单行线,你可以做这样的事情

logger.info Benchmark.measure do 
    (@cv.desired_occupations + @cv.past_occupations).each do |occupation| 
    section = [] 
    section << 'Desired occupation' if @cv.desired_occupations.include? occupation 
    section << 'Work experience' if @cv.past_occupations.include? occupation 

    unless (array = @occupation_hashes.assoc(occupation)).blank? 
     array[1] += 1 
     array[2] = (array[2] & section).uniq 
    else 
     @occupation_hashes << [occupation, 1, section] 
    end 
    end 
end 

我刚开始用大块,然后缩小它下。不知道你处理的数据集有多大,很难说问题区是什么。

我也会同意别人,你会更好地把这件事分解成更小的方法。这也将使测试性能变得更容易,因为您可以做这样的事情:

Benchmark.measure { 10000.times { foo.do_that_thing_that_might_be_slow }}