为什么我的Ruby脚本会随着时间的推移而变慢?
我有一个2.6GB的文本文件,其中包含一个数据库表的转储,我正试图将其拉入一个逻辑结构,以便所有字段都可以唯一化。我使用的代码如下:为什么我的Ruby脚本会随着时间的推移而变慢?,ruby,performance,file-io,class-method,Ruby,Performance,File Io,Class Method,我有一个2.6GB的文本文件,其中包含一个数据库表的转储,我正试图将其拉入一个逻辑结构,以便所有字段都可以唯一化。我使用的代码如下: class Targetfile include Enumerable attr_accessor :inputfile, :headers, :input_array def initialize(file) @input_array = false @inputfile = File.open(file, 'r') @x
class Targetfile
include Enumerable
attr_accessor :inputfile, :headers, :input_array
def initialize(file)
@input_array = false
@inputfile = File.open(file, 'r')
@x = @inputfile.each.count
end
def get_headers
@y = 1
@inputfile.rewind
@input_array = Array.new
@headers = @inputfile.first.chomp.split(/\t/)
@inputfile.each do |line|
print "\n#{@y} / #{@x}"
@y+=1
self.assign_row(line)
end
end
def assign_row(line)
row_array = line.chomp.encode!('UTF-8', 'UTF-8', :invalid => :replace).split(/\t/)
@input_array << Hash[ @headers.zip(row_array) ]
end
def send_build
@input_array || self.get_headers
end
def each
self.send_build.each {|row| yield row}
end
end
类目标文件
包括可枚举的
attr\u访问器:inputfile,:headers,:input\u数组
def初始化(文件)
@输入数组=false
@inputfile=File.open(文件'r')
@x=@inputfile.each.count
终止
def get_标题
@y=1
@inputfile.rewind
@input_array=array.new
@headers=@inputfile.first.chomp.split(/\t/)
@inputfile.do每行|
打印“\n{@y}/{@x}”
@y+=1
自分配_行(行)
终止
终止
def分配_行(行)
行数组=line.chomp.encode!('UTF-8','UTF-8',:无效=>:替换)。拆分(/\t/)
@这就是臭名昭著的垃圾收集器——Ruby的内存管理机制
注意:值得一提的是Ruby,至少是MRI,不是一种高性能语言
每当内存开始耗尽时,垃圾收集器就会运行。垃圾收集器暂停程序的执行,以取消分配任何无法再访问的对象。垃圾收集器仅在内存开始耗尽时运行。这就是为什么你会定期看到它
除了编写更多内存效率高的代码,或者用一种能够更好地/手动管理内存的语言重写之外,您无法避免这种情况
此外,您的操作系统可能正在分页。你有足够的物理内存来完成这类任务吗?这就是臭名昭著的垃圾收集器——Ruby的内存管理机制
注意:值得一提的是Ruby,至少是MRI,不是一种高性能语言
每当内存开始耗尽时,垃圾收集器就会运行。垃圾收集器暂停程序的执行,以取消分配任何无法再访问的对象。垃圾收集器仅在内存开始耗尽时运行。这就是为什么你会定期看到它
除了编写更多内存效率高的代码,或者用一种能够更好地/手动管理内存的语言重写之外,您无法避免这种情况
此外,您的操作系统可能正在分页。你有足够的物理内存来完成这类任务吗?我建议用DBM,而不是Ruby或任何其他语言。DBM可以非常快速地告诉您字段的唯一值,尤其是在它已经被索引的情况下
在任何语言中尝试这样做都是在为通用计算设计的东西中复制数据库的基本功能
相反,将Ruby与类似于Sequel或Active Record的ORM一起使用,并向数据库发出查询,让它返回您想知道的内容。不要迭代每一行,这太疯狂了,让它给你唯一的值,然后从那里开始
我不会责怪Ruby,因为如果使用相同的主机和RAM,任何其他语言都会出现同样的问题。C/C++可能会通过生成更紧凑的代码来延迟不可避免的任务,但您的开发时间会急剧放缓,特别是当您学习像C这样的未知语言时。由于您必须比Ruby、Python或Perl进行更多的内务管理和防御性编程,因此发生意外错误的风险会增加
使用每一种工具的目的是什么,你会领先
查看您的代码,您可以通过不尝试在内存中保留每一行来提高完成整个运行的机会。您说过您正在尝试确定唯一性,所以只保留您感兴趣的唯一列值,这可以使用Ruby的Set类轻松完成。您可以将要确定唯一性的每件事情的值抛出,遍历文件,Set将只保留唯一值。我建议使用DBM,而不是Ruby或任何其他语言。DBM可以非常快速地告诉您字段的唯一值,尤其是在它已经被索引的情况下
在任何语言中尝试这样做都是在为通用计算设计的东西中复制数据库的基本功能
相反,将Ruby与类似于Sequel或Active Record的ORM一起使用,并向数据库发出查询,让它返回您想知道的内容。不要迭代每一行,这太疯狂了,让它给你唯一的值,然后从那里开始
我不会责怪Ruby,因为如果使用相同的主机和RAM,任何其他语言都会出现同样的问题。C/C++可能会通过生成更紧凑的代码来延迟不可避免的任务,但您的开发时间会急剧放缓,特别是当您学习像C这样的未知语言时。由于您必须比Ruby、Python或Perl进行更多的内务管理和防御性编程,因此发生意外错误的风险会增加
使用每一种工具的目的是什么,你会领先
查看您的代码,您可以通过不尝试在内存中保留每一行来提高完成整个运行的机会。您说过您正在尝试确定唯一性,所以只保留您感兴趣的唯一列值,这可以使用Ruby的Set类轻松完成。您可以抛出每个要确定唯一性的对象的值,遍历文件,Set将只保留唯一值。您正在使用头作为散列的键。它们是字符串,散列重复字符串键。这是许多不必要的字符串。如果将它们转换为符号可以加快速度,请尝试:
@headers = @headers.map{|header| header.to_sym}
您正在使用头作为散列的键。它们是字符串,散列重复字符串键。这是许多不必要的字符串。如果将它们转换为符号可以加快速度,请尝试:
@headers = @headers.map{|header| header.to_sym}
这是垃圾收集器。您可以通过在程序中放入GC.start来强制垃圾收集。让它定期运行。
我必须为我编写的守护进程做同样的事情。它工作得很好。
这是垃圾收集器。您可以通过放入GC.star强制垃圾收集