我有以下用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
答案 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时执行。