ruby中的递归方法性能

时间:2014-05-08 11:59:01

标签: ruby recursion

我有以下用ruby编写的recusive函数但是我发现该方法运行得太慢了。我不确定这是否正确,如果你可以建议我提高这段代码的性能。我会非常感激。此外,包括子目录在内的总文件数为4,535,347

    def start(directory)
      Dir.foreach(directory) do |file|
       next if file == '.' or file == '..'
       full_file_path = "#{directory}/#{file}"
       if File.directory?(full_file_path)
        start(full_file_path)
       elsif File.file?(full_file_path)
        extract(full_file_path)
       else
        raise "Unexpected input type neither file nor folder"
       end
    end

2 个答案:

答案 0 :(得分:3)

使用4.5M目录,您可能最好使用专门的惰性枚举器,以便只处理您实际需要的条目,而不是生成这些4.5M列表中的每一个,返回整个集合并迭代它整个。

以下是文档中的示例:

class Enumerator::Lazy
  def filter_map
    Lazy.new(self) do |yielder, *values|
      result = yield *values
      yielder << result if result
    end
  end
end

(1..Float::INFINITY).lazy.filter_map{|i| i*i if i.even?}.first(5)

http://ruby-doc.org/core-2.1.1/Enumerator/Lazy.html

这不是一个很好的例子,顺便说一下:重要的部分是Lazy.new(),而不是Enumerator::Lazy被猴子修补的事实。这是一个更好的例子imho:

What's the best way to return an Enumerator::Lazy when your class doesn't define #each?

进一步阅读该主题:

http://patshaughnessy.net/2013/4/3/ruby-2-0-works-hard-so-you-can-be-lazy

您可能需要考虑的另一个选项是跨多个线程计算列表。

答案 1 :(得分:2)

我认为没有办法加快你的start方法的速度;它可以正确处理您的文件并在遇到它们时立即处理它们。您可以使用单个Dir.glob do来简化它,但它仍然会很慢。我怀疑这不是花费的大部分时间。

很可能有一种方法可以加速你的extract方法,没有代码就无法知道。

加快这种速度的另一种方法可能是将处理拆分为多个进程。自阅读&amp;写作可能会减慢你的速度,这种方式会让你希望ruby代码在另一个进程等待IO时执行。