ruby - 如何提高将文件转换为哈希数组的过程性能?

标签 ruby activerecord activerecord-import

我正在使用这种方法来处理一个大约有 220,000 行的文本文件。 处理一个需要几分钟,但我有很多。是否有任何建议可以加快此过程?

def parse_list(file_path,import=false)
# Parse the fixed-length fields
   if File.exist?(file_path)
     result=[]
     File.readlines(file_path)[5..-1].each do |rs|
        if rs.length > 140
          r=rs.strip
          unless r=='' 
            filing={
                  'name' => r[0..50].strip,
                  'form' => r[51..70].strip,
                  'type'  => r[71..80].strip,
                  'date' => r[81..90].strip,
                  'location' => r[91..-1].strip
                  }     
              result.push(filing)
          end
        end
     end
     return result
   else
     return false
   end
end

更新:

最初,我认为使用 Nex 和 thetinman 的方法可以节省大量时间,所以我继续测试它们以保持解析方法的一致性。

使用我原来的 r[].strip 解析方法,但使用 Nex 的 each_line block 方法和 thetinman 的 foreach 方法:

Rehearsal ---------------------------------------------
Nex         8.260000   0.130000   8.390000 (  8.394067)
Thetinman   9.740000   0.120000   9.860000 (  9.862880)
----------------------------------- total: 18.250000sec

                user     system      total        real
Nex        14.270000   0.140000  14.410000 ( 14.397286)
Thetinman  19.030000   0.080000  19.110000 ( 19.118621)

使用thetinman的unpack.map解析方式再次运行:

Rehearsal ---------------------------------------------
Nex         9.580000   0.120000   9.700000 (  9.694327)
Thetinman  11.470000   0.090000  11.560000 ( 11.567294)
----------------------------------- total: 21.260000sec

                user     system      total        real
Nex        15.480000   0.120000  15.600000 ( 15.599319)
Thetinman  18.150000   0.070000  18.220000 ( 18.217744)

unpack.map(&:strip) vs r[].strip:unpackmap 做似乎并没有提高速度,但在未来是一个有趣的方法。

我发现了一个不同的问题:随着发现大量时间的节省,我想,我继续使用 pry 手动运行 Nex 和 thetinman 的方法。这是我发现我的电脑挂起的地方,就像我的原始代码一样。所以我继续再次测试,但使用的是我的原始代码。

Rehearsal ---------------------------------------------
Original    7.980000   0.140000   8.120000 (  8.118340)
Nex         9.460000   0.080000   9.540000 (  9.546889)
Thetinman  10.980000   0.070000  11.050000 ( 11.042459)
----------------------------------- total: 28.710000sec

                user     system      total        real
Original   16.280000   0.140000  16.420000 ( 16.414070)
Nex        15.370000   0.080000  15.450000 ( 15.454174)
Thetinman  20.100000   0.090000  20.190000 ( 20.195533)

我的代码、Nex 和 thetinman 的方法似乎具有可比性,Nex 是使用 Benchmark 时最快的。然而,Benchmark 似乎并不能说明全部情况,因为使用 pry 手动测试代码会使所有方法花费更长的时间,以至于我在取回结果之前就取消了。

我还有一些问题:

  1. 在 IRB/Pry 中运行类似的东西是否会产生这些奇怪的结果,从而使代码运行速度大大降低?
  2. 如果我运行 original_method.countnex_method.countthetinmans_method.count,它们似乎都能快速返回。
  3. 由于内存问题和可扩展性,thetinman和nex建议不要使用原来的方法。但是,将来是否有办法使用基准测试之类的方法来测试内存使用情况?

NEX 更新,使用 activerecord-import:

@nex,这是你的意思吗?这对我来说似乎仍然运行缓慢,但我不确定你说的是什么意思:

import one set of data inside that block.

您建议如何修改它?

def parse_line(line)
   filing={
   'name' => line[0..50].strip,
   'form' => line[51..70].strip,
   'type'  => line[71..80].strip,
   'date' => line[81..90].strip,
    'location' => line[91..-1].strip
    }    
end

def import_files
 result=[]
 parse_list_nix(file_path){|line|
    filing=parse_line(line)    
    result.push(Filing.new(filing))

 }
 Filing.import result   #result is an array of new records that are all imported at once
end

如您所见,activerecord-import 方法的结果要慢得多:

Rehearsal ------------------------------------------
import 534.840000   1.860000 536.700000 (553.507644)
------------------------------- total: 536.700000sec

             user     system      total        real
import 263.220000   1.320000 264.540000 (282.751891)

这个缓慢的导入过程看起来正常吗?

它对我来说太慢了。我想弄清楚如何加快速度,但我没有主意。

最佳答案

没有样本数据很难证实这一点,但是,根据原始代码,我可能会这样写:

require 'english'

# Parse the fixed-length fields
def parse_list(file_path,import=false)

  return false unless File.exist?(file_path)

  result=[]
  File.foreach(file_path) do |rs|
    next unless $INPUT_LINE_NUMBER > 5
    next unless rs.length > 140

    r = rs.strip
    if r > '' 
      name, form, type, date, location = r.unpack('A51 A20 A10 A10 A*').map(&:strip)
      result << {
        'name'     => name,
        'form'     => form,
        'type'     => type,
        'date'     => date,
        'location' => location
      }
    end
  end

  result
end

220,000 行对我来说不算大文件。到中午时分,我们得到的日志文件是原来的 3 倍,因此使用任何吞噬文件的文件 I/O 都被淘汰了。 Ruby 的 IO 类有两个用于逐行 I/O 的方法和一个返回数组的数字。你想要前者,因为它们是可扩展的。除非你能保证正在读取的文件能很好地适应 Ruby 的内存,否则请避免后者。

关于ruby - 如何提高将文件转换为哈希数组的过程性能?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16491812/

相关文章:

ruby-on-rails - 在 ruby​​ 中按年龄范围对用户进行分组

mysql - 将大型数据集加载到 Rails 应用程序中

ruby-on-rails - 是否可以将 'activerecord-import' gem 用于 Rails 中的无模型表?

ruby-on-rails - 用 Solr 全文搜索不规则的说唱歌手名字

Ruby 正则表达式匹配字符串前面有数字范围

ruby - 使用 ruby​​ watir 测试 html 表格元素是否存在

ruby - 设置环境变量,无需在字符串和整数之间进行转换

mysql - rails : Scopes to find records where previous years of the same customer records exist

ruby-on-rails - rails object.association.count postgres 错误