1

データベース テーブルのダンプを含む 2.6 ギガバイトのテキスト ファイルがあり、フィールドをすべて一意にできるように、それを論理構造に取り込もうとしています。これを行うために使用しているコードは次のとおりです。

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

クラスは正常に初期化され、Targetfile クラス オブジェクトが残ります。

get_headers問題は、ファイルをハッシュの配列に変換するメソッドを呼び出すと、すぐに速度が低下し始めることです。

これは項目番号 80,000 あたりまでは目立ちませんが、ファイルの 3 ~ 4,000 行ごとに何らかの一時停止が発生していることが明らかになります。この一時停止は、発生するたびに少し長くかかり、100 万行目までは 30 秒以上かかります。

実際には、ファイルを切り刻んでこの問題を回避し、結果のリストと一意の -that- を組み合わせて、最終的な出力を得ることができます。

しかし、好奇心の観点からは、私は満足していません。

なぜこの一時停止が発生するのか、なぜ長くなるのか、それをエレガントに回避する方法があるのか​​ 誰か教えてもらえますか? 本当に私はそれが何であり、なぜそれが起こるのかを知りたいだけです.なぜなら、私がそれに気づいたので、このコンピューターと他のコンピューターの両方で実行する他の多くのRubyスクリプトで見られるからです.

4

4 に答える 4

3

Rubyや他の言語ではなく、DBMでこれを行うことをお勧めします。DBM は、特にすでにインデックスが作成されている場合、フィールドの一意の値を非常に迅速に伝えることができます。

どの言語でもこれを行おうとすると、データベースの基本的な機能を一般的なコンピューティング用に設計されたものに複製することになります。

代わりに、Sequel や Active Record などの ORM で Ruby を使用し、データベースにクエリを発行して、知りたいことを返してもらいます。すべての行を反復しないでください。それは狂気です。一意の値を指定してそこから移動するように依頼してください。

同じホストと RAM が与えられた他の言語でも同じ問題が発生するため、Ruby を責めるつもりはありません。C/C++ は、よりコンパクトなコードを生成することで避けられない事態を遅らせる可能性がありますが、特に C のような未知の言語を学習する場合は、開発時間が大幅に遅くなります。 Ruby、Python、または Perl で行うよりもプログラミングが簡単です。

それぞれのツールを目的に合わせて使用​​すれば、先を行くことができます。

コードを見ると、すべての行をメモリに保持しようとしないことで、完全に実行できる可能性が高くなる可能性があります。一意性を判断しようとしていると言ったので、関心のある一意の列値のみを保持します。これは、Ruby の Set クラスを使用して簡単に行うことができます。一意性を判断したいそれぞれの値をスローし、ファイルをウォークすると、Set は一意の値のみを保持します。

于 2013-09-13T21:49:19.003 に答える
1

これは、悪名高いガベージ コレクター (Ruby のメモリ管理メカニズム) です。

注: Ruby、少なくとも MRI は高性能言語ではないことに注意してください。

ガベージ コレクタは、メモリが不足し始めるたびに実行されます。ガベージ コレクターは、プログラムの実行を一時停止して、アクセスできなくなったオブジェクトの割り当てを解除します。ガベージ コレクターは、メモリが不足し始めたときにのみ実行されます。そのため、定期的に表示されます。

これを回避するためにできることはありませんが、メモリ効率の高いコードを記述するか、より優れた/手動のメモリ管理が可能な言語で書き直すことを除きます。

また、OS がページングしている可能性があります。この種のタスクに十分な物理メモリがありますか?

于 2013-09-13T21:28:12.400 に答える
0

ヘッダーをハッシュのキーとして使用しています。それらは文字列であり、重複する文字列キーをハッシュします。それは多くの不要な文字列です。それらをシンボルに変換すると速度が上がるかどうか試してください。

@headers = @headers.map{|header| header.to_sym}
于 2013-09-13T22:01:47.090 に答える