かなり迅速かつ効率的な方法で、ギグまでの大きなデータファイルをスライスアンドダイスしたいと思います。UNIXの「CUT」みたいなものを使えば、CYGWIN環境でもめちゃくちゃ速いです。
これらのファイルを処理するために、さまざまな Ruby スクリプトの開発とベンチマークを試みましたが、常に最終的な結果が得られませんでした。
これをそれほど遅くしないためにRubyで何をしますか?
かなり迅速かつ効率的な方法で、ギグまでの大きなデータファイルをスライスアンドダイスしたいと思います。UNIXの「CUT」みたいなものを使えば、CYGWIN環境でもめちゃくちゃ速いです。
これらのファイルを処理するために、さまざまな Ruby スクリプトの開発とベンチマークを試みましたが、常に最終的な結果が得られませんでした。
これをそれほど遅くしないためにRubyで何をしますか?
この質問は、Tim Bray のWide Finder プロジェクトを思い出させます。彼が Ruby を使用して Apache ログファイルを読み取り、最も多く取得された記事を特定する最速の方法は、次のスクリプトを使用することでした。
counts = {}
counts.default = 0
ARGF.each_line do |line|
if line =~ %r{GET /ongoing/When/\d\d\dx/(\d\d\d\d/\d\d/\d\d/[^ .]+) }
counts[$1] += 1
end
end
keys_by_count = counts.keys.sort { |a, b| counts[b] <=> counts[a] }
keys_by_count[0 .. 9].each do |key|
puts "#{counts[key]}: #{key}"
end
昨年の 1.67Ghz PowerBook では、このコードが 100 万件の変更レコードを処理するのに 7.5 秒の CPU を使用し、13.5 秒経過しました。
それらを組み合わせてみませんか? cut を使用して最適な処理を行い、ruby を使用して CUT の結果に接着剤/付加価値を提供しますか? 次のようにバッククォートでシェル スクリプトを実行できます。
puts `cut somefile > foo.fil`
# process each line of the output from cut
f = File.new("foo.fil")
f.each{|line|
}
あなたの Ruby 実装は、処理前にファイル全体を読み取っていると思います。Unix のカットは、一度に 1 バイトずつ読み取り、すぐに出力ファイルにダンプすることで機能します。もちろん、多少のバッファリングが含まれますが、数 KB を超えることはありません。
私の提案: ページングやバックトラッキングをできるだけ少なくして、その場で処理を行ってみてください。
問題は、rubyがメモリ内のファイル全体を読み取っているということではないかと思います。コマンドの実行中にメモリとディスクの使用量を調べて確認します。
主な理由は、カットがCで書かれていて、1つのことしか行っていないためだと思います。したがって、おそらくそれは非常に金属にコンパイルされています。おそらく、システムコールを呼び出す以上のことはしていません。
ただし、ルビーバージョンは一度に多くのことを実行しています。rubyでは、メソッドの呼び出しはC関数の呼び出しよりもはるかに低速です。
UNIXで老後とトレチャリーが若者とスキルを打ち負かしたことを覚えておいてください:http://ridiculousfish.com/blog/archives/2006/05/30/old-age-and-treachery/