【问题标题】:Recursive method performance in RubyRuby 中的递归方法性能
【发布时间】:2014-06-25 19:19:06
【问题描述】:

我有以下用 Ruby 编写的递归函数,但是我发现该方法运行得太慢了。我不确定这是否是正确的方法,所以请建议如何提高此代码的性能。包括子目录在内的总文件数为 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

【问题讨论】:

  • 那个函数的目的是什么?我认为它可以用更具体的东西代替

标签: ruby recursion


【解决方案1】:

对于 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 得到猴子补丁的事实。这是一个更好的例子恕我直言:

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

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

【讨论】:

  • 这在 ruby​​ 1.9.2 上也可用吗?
  • 如果你使用 ruby​​ 1.9.2 你至少应该在标签中指定它
  • @xecutioner:不,这是 Ruby 2 的特性。
  • 恐怕懒惰的枚举器不会让这个更快。 OP 发布的代码不会错误地返回完整列表,而是一个接一个地处理每个文件。惰性枚举器将给出相同的结果。
  • 此外,使用 lazy 枚举器与在此处使用标准枚举器没有区别。
【解决方案2】:

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

很可能有一种方法可以加快您的extract 方法,没有代码就不可能知道。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-26
    • 1970-01-01
    • 2018-05-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多