2009-04-09 18 views
3

Perl readdirを使用してファイルのリストを取得していますが、ディレクトリに250,000を超えるファイルが含まれているため、readdirを実行するのに長時間(4分以上)がかかるため、80MB以上のRAMを使用します。これは5分ごとに定期的な仕事を予定していたため、この遅延時間は受け入れられません。250,000ファイルのディレクトリに対してPerlのreaddirをスピードアップするにはどうすればよいですか?

詳細情報: 別のジョブでは、スキャン中のディレクトリ(1日に1回)がいっぱいになります。 このPerlスクリプトは、ファイルの処理を行います。ファイル数はスクリプトの反復ごとに指定され、現在は実行ごとに1000回です。 Perlスクリプトは5分ごとに実行され、1000個までのファイルを処理します(該当する場合)。 Perlが複雑なワークフローを引き起こすデータをデータベースにプッシュする際に、ダウンストリーム処理を継続できるようにするためのファイル数の制限。

ディレクトリからファイル名を取得する別の方法があります。理想的にはこのスクリプトの速度を大幅に向上させる1000(変数で設定)に制限されていますか?

答えて

8

readdirが分と80 MBを取っていると正確にはどういう意味ですか?その特定のコード行を表示できますか?スカラーコンテキストまたはリストコンテキストでreaddirを使用していますか?

あなたはこのような何かをやっている:

foreach my $file (readdir($dir)) { 
    #do stuff here 
} 

をそのような場合は、メモリにリストディレクトリ全体を読んでいます。長い時間と多くの記憶が必要なのは不思議ではありません。

この投稿の残りの部分は、リストの文脈でreaddirを使用していない場合、これが問題であるとみなし、残りの投稿を無視します。

この問題を解決するには、whileループを使用し、スカラーコンテキストでreaddirを使用します。

while ( 
    defined(my $file = readdir $dir) 
) { 

    # do stuff. 

} 

これで、一度に1つのアイテムのみを読むようになりました。処理するファイルの数を追跡するためにカウンタを追加することもできます。

+0

ブリリアント。私は戻っていくつかのディレクトリアクセスをリファクタリングする必要があるかもしれません! –

+1

定義済みのものは暗黙的ですが、(my $ file = readdir $ dir){}はOKです –

+1

これは私の問題を解決しました。また、希望のしきい値で停止できるように検索されたファイル名の数を厳密に制御することもできます。ありがとう、daotoad。 – Walinmichi

0

おそらくそうではありません。私はほとんどの時間は、ディレクトリエントリを読み取っていると思います。

しかし、あなたが前処理全体のディレクトリ1000のエントリごとに1ファイルを作成し、リストアップできました。そして、あなたのプロセスはそのたびにこれらのリストファイルの1つを実行し、ディレクトリ全体を読み取る費用を負担することはありません。

readdir()は、ベースラインを得るために他の処理を行わないでディレクトリに入力してみましたか?

+0

はい、私は(> 4分)に提供されたデータは、ちょうどのreaddir操作です。テストのプロセス数を1に設定しました。 – Walinmichi

7

ソリューションは多分もう一方の端にあるのでしょう:ディレクトリを埋めるスクリプトで...

をすべてのこれらのファイルを格納するための樹枝を作成し、その方法は、管理可能な数とディレクトリの多くそれぞれを持っていないのはなぜのファイルですか?

代わりの "mynicefile.txt" なぜ "M /私/ mynicefile"、またはそのような何かを作りますか?

お使いのファイルシステムは、(あなたも一緒に終了したときに、空のディレクトリを削除する場合は特に)そのためにあなたに感謝します。

+1

+1、私は一般的に1000ファイルの下にフォルダを保持しようとすると、それ以上のファイルシステムstat()コールはちょうどチャンク自体を呼び出します。 –

+0

"医者、医者!私が手首に触れると痛い。" "まあ、解決は簡単です。それをやめてください!" –

+0

だから、ミスターブードゥー博士:あなたの魔法の解決策について教えてください。私も興味があります(しかし、その過程で動物を犠牲にしたくはありません) – siukurnin

1

これはまさにあなたのクエリへの答えではありませんが、私は同じディレクトリに多数のファイルが(ファイルシステムのハンドルが操作を追加および削除する速度、を含む全体的な速度のために非常に良いことではないことを持つと思いますあなたが見ただけでなく、リストに載せます)。

この設計上の問題を解決するには、ファイル名の最初の文字ごとにサブディレクトリを作成し、そのディレクトリ内にその文字で始まるすべてのファイルを配置することです。必要に応じて、2番目、3番目などの文字に再帰します。

may操作では、明らかに速度の向上が見られます。

+0

私はファイルの埋め込み部分を制御できません。それは圧縮されていないzipファイルのFTPプルです。より頻繁な投稿スクリプトによって使用されるファイル名を持つ単一のファイルを作成するために1時間に1回程度実行される別のスクリプトを作成することを考えます。 – Walinmichi

2

あなたは、コンテンツがZIPファイルを解凍してそこに到着したと言っています。 1つのディレクトリに250kのファイルを作成/使用するのではなく、zipファイルで作業してみませんか?基本的には

- それをスピードアップするために、あなたはPerlで、ではなく、ファイルシステムレベルでの具体的なものを必要としません。あなたがディレクトリ内の250kファイルで作業しなければならないことを100%確信しているなら(これは何かが必要な状況を想像することはできません)、あなたはそれを扱うためにファイルシステムを見つけることよりもずっと良いですそれをより速くスキャンするperlの "魔法の"モジュールです。

+0

圧縮zipファイルの操作方法がわかりません。私はファイルハンドルを知っているかもしれないし、別のプロセスから取得するかもしれないので、通常は問題ではありません。この場合、私は自分のコントロール外の別のプロセスからファイルを "ダンプ"しています。 – Walinmichi

+0

@unknown - Archive :: Zipを使用してzipファイルを操作できます。 –

0

あなたはreaddirをスピードアップするつもりはありませんが、ディレクトリを監視する作業をスピードアップすることができます。あなたはOSにアップデートを求めることができます - 例えば、Linuxはinotifyを持っています。ここではそれを使用する方法についての記事です:

http://www.ibm.com/developerworks/linux/library/l-ubuntu-inotify/index.html?ca=drs-

あなたはPerlのからバージョンinotifyを使用することができます。

http://metacpan.org/pod/Linux::Inotify2

差があなたの代わりにあるスクリプトの1長時間実行アプリを持っているということですcronによって始まりました。このアプリケーションでは、(inotifyによって提供される)新しいファイルのキューを保持します。次に、タイマーを5分ごとにオフにして、1000個のアイテムを処理します。その後、制御はイベントループに戻り、5分後に起きて1000個以上のアイテムを処理するか、inotifyはキューに追加するファイルをさらに送信します。

(ところで、あなたはタイマーを処理するためにイベントループが必要になります。私はEVをお勧めします。)

関連する問題