すべてのカテゴリ » インターネット・パソコン » 技術・プログラミング

質問

終了

プログラムに詳しい方!教えてください!

大量にあるテキストファイルから、一部を取り出すプログラムを作っています。
とりあえず「一部を取り出す」ことはできたのですが、ファイル数が多いので時間がかかってしまいます。(大体5万ファイルくらいある)
CPUは20%程しか使っていない状態なので、もっと働かせれば時間短縮になると思うのです。

簡単にCPUをもっと働かせる方法はないでしょうか?
言語はPerlで、OSはMacです。

  • 質問者:あんぐりら
  • 質問日時:2009-03-23 16:39:56
  • 0

Perlスクリプトをバックグラウンドで複数動作させるApplescriptを作ってみてはどうでしょうか。

1.いまあるPerlスクリプトに引数を追加する。
 追加する引数は開始ファイルと終了ファイルとし、
 指定されたファイルのみ処理を行う様にする。
 例)Perl hoge.pl 00001.txt 00100.txt
2.改良したPerlスクリプトをバックグラウンド動作させる。
 例)Perl hoge.pl 00001.txt 00100.txt 0 > /dev/null 2>&1 &
3.Applescriptから、5万ファイル分ループさせる。
 例)
 repeat with i from 1 to TO_NO by 1000
  set from to 開始ファイルの名前を作る処理
  set to to 終了ファイルの名前を作る処理
  set cmd to "Perl hoge.pl " & from & " " & to & " "0 > /dev/null 2>&1 &"
  do shell script cmd
 end repeat

これで複数のPerlが同時に動くようになるので、CPUも効率よく動くかもしれません。

===補足===
"> /dev/null"では、標準出力に出力されるデータを"/dev/null"に出力する様にしています。
"/dev/null"は特別なディレクトリで、ここに出力した物は何も処理されずに捨てられてしまいます。
そのため、データ出力時の時間も短縮できます。
"2 > &1"では、、標準出力に出力されるエラーを"&1"に出力する様にしています。
この時"&1"は"/dev/null"を指すので、エラーも処理されずに捨てられます。
最後の"&"は、バックグラウンドで処理するという意味です。

合わせると「出力されるデータ・エラーを捨てて、バックグラウンドで呼び出す」となります。

  • 回答者:僕らは目指した (質問から1日後)
  • 0
この回答の満足度
  
とても参考になり、非常に満足しました。回答ありがとうございました。
お礼コメント

perl実行時の"> /dev/null 2>&1 &"は何でしょうか?

並び替え:

CPU演算速度よりも、
ファイルアクセスに要する時間(HDDからの読込み速度)の方が
ネックになりますので、
単純には、CPU使用率を上げても処理時間は向上しないでしょう。

テキストファイルから抜出す検索文字列のアルゴリズムを
特定条件に特化して処理速度向上するように改善するか、

あるいは、
使用している言語の文字列操作に関する命令ステートメントの変更

例えば、
Visual Basic などなら、Left/Mid 関数でなく、
Left$/Mid$ の文字列指定の関数の使用や、
文字列連結は "&"演算子ではなく、
Join関数やMid方法と云われている手法などを使用。

といった改善を目指したほうが、効率的になるかと思います。

またまた、あるいは、
テキストファイルの事前処理として、
なんらかのインデックス(抜出す内容の検索が向上するような仕組み)
を作成するのも有効かもしれませんね。

  • 回答者:カズ (質問から42分後)
  • 0
この回答の満足度
  
参考になりました。回答ありがとうございました。
お礼コメント

Visual Basicのやり方をPerlやMacではどうやれば良いですか?
インデックスとはどういった物でしょうか?

物理的に複数のドライブにファイルを分けて,同時に同じプログラムを走らせればいいだけでは?
同じドライブだとディスクのI/O待ちでその辺が限界だと思います.

どういうプログラムか不明ですが,Perlの場合,1行ずつ読み込むなんて書き方をしてると遅くなるでしょうねぇ*先頭のほうに目標が固まっているなら別ですが.
5万ファイルくらいで遅さが問題になるのは元々のプログラムの書き方がマズイのだと思いますよ(めちゃくちゃデカイのですかねぇ).
今,提示されている条件から言えるのはこの程度です.

===補足===
まだ解決してなかったんですか.(;´ω`)
反応無いので解決したか放置だと思ってました.(;´ω`)

同じプログラムを同時に走らせるには…って,ただの Perl スクリプトなので,バックグラウンドで実行させれば済むし…シェル(というかターミナル)を2つ開いて,それぞれで実行させても構いませんよねぇ.但し,同じ物理ディスクに対してモリモリ要求を出してI/O待ちが長くなるだけのケースもありますから有効かどうかはやってみないと分かりません.

いっぺんに読み込むのは http://www2u.biglobe.ne.jp/~MAS/perl/waza/fonestr.html を参考にどうぞ.

最初の質問に書かれてなくて,コメントで明確ではないけど少し想像できたこと…「目標は複数」という「目標」は「ファイル」であって,ディレクトリのどこにあるか分からないので readdir しながら辿っていかないといけない…ということですか?深い階層が存在するのであれば,オンメモリの量も増えるし,結構遅いかも…MacOS X で測定したことはないけど,普通,重いです.
「目標」が「ファイル内の検索対象文字列」であり,「1つのファイル中に1箇所とは限らないので全部ナメるしかない」かつファイル自体は特定のディレクトリに存在しててるのなら検索方法を改善…しなくても,物理的にファイルの置き場所を分けてやり,抽出すればよいと思いますが….
物理的に分けるって運用はできないということですかねぇ.
そんで,抽出する情報もどういうのが必要なのか…キーワードを含むファイル名なのか,ファイル名とキーワードが含まれる行番号なのかファイル先頭からのオフセットなのか…といった条件も回答に期待される場合は必要です.

実行条件を正確に提示されていないので,回答しにくいというか,回答しても条件に合うのかどうか分からないんですけど…回答の補足は1回しか書けないので,役に立たないことしか書いていないのかもしれません.
というか,問題点を最初から書いて…できれば遅い部分をプロファイラを入れ込んで明らかにした上で,対象を絞って条件を明確にしてから質問してほしいんですが…絞り込み自体も難しいですかねぇ(難しければ無理にとは言いませんが,どういう条件の元で,どういうソースを書いたくらいは書いてもらわないと改善のしようがありませんが…).(;´ω`)

それと,「時間短縮」したいのですよね…そもそも5万ファイルの処理時間がどれくらいで,それをどの程度まで縮めたいのでしょうか?あまりに無茶な時間短縮を望んでおられる場合,コンパイル言語を使うほうがよい場合もありますし,そもそも無理って場合もあります.

カズさんの回答へのコメントを見ると…文字列検出の速度が遅いんですかね…一体,今,どういう検出方法を採用しておられるのでしょう…ここが問題ならそれを晒して質問するほうが解決は早いと思いますけど….Perlで行の中から文字列を検索するという場合,正規表現を使うことが多いと思いますけど…不必要な複雑さをもたせていると遅くなることもあるでしょうねぇ…くらいしか書けません.(;´ω`)

う~みゅ…「perl実行時の"> /dev/null 2>&1 &"は何でしょうか?」をコメントに書いているとこを見ると,そもそもOS(unix系)の使い方とか bash の使い方とかを知らない…ということですねぇ.
これは由々しき問題です(お勉強が決定的に不足していますよ).(;´ω`)

この回答の満足度
  
回答ありがとうございました。
お礼コメント

1ファイル1,000行で文字数は4万くらいです。
目標は複数あって、どこにあるかは分かりません。

同時に同じプログラムを走らせる方法や、1行ずつ読み込まない方法は具体的にどうすればいいでしょうか?

Windows使いなので、詳しくはわかりませんが、CPU20%なら十分なのではないでしょうか。これ以上、パソコンに付加をかけてもOSの動作が固まったかのような動きになると思います。

この回答の満足度
  
参考になり、満足しました。回答ありがとうございました。

関連する質問・相談

Sooda!からのお知らせ

一覧を見る