/XX/XX/XX/
各ファイルの内容を処理するために、サブディレクトリにある何百万ものファイルを読みました。 PHPでは、次のようにファイルを読みました。
foreach(glob("/folder/*") as $a){
foreach(glob("$a/*") as $b){
foreach(glob("$b/*") as $c){
foreach(glob("$c/*") as $file){
// Processing
}
}
}
}
問題は、このコードは特定の順序でファイルを取得しますが、可能な順序で(最小検索時間で)すべてのファイルを読み取る必要があることです。
ナビゲーション時間を短縮するためにHDDセクタに保存されているファイルを読み取る方法はありますか?
PHPコードは私がここに来た方法を示すためのものであり、PHPで解決策を見つけることを期待していません。私の質問は実際にshell
。
修正する:
私は問題を明確に説明しませんでした。すでに完全なファイルのリストがあります。問題はそれを見つけるのではなく、ナビゲーション時間を短縮するためにコンテンツを読むのに最適な順序です。
glob
代わりに使ってみました
foreach($files as $file){
$content=file_get_contents($file);
}
各ファイルの検索時間を短縮したい。
前述したように、言語は重要ではありません。 bashまたはCでコード全体を書き換えることができます。
私の質問を再現しましょう。入れ子になったフォルダ(HDD、ext4を含む)に保存されている何百万ものファイルの内容を最も速く読み取るには?
答え1
ここで「HDDセクタ」は重要ではない。フォルダの内容が保存されアクセスされる方法は、ストレージデバイスのブロック構造とほとんど関係ありません(ただし、ファイルシステムによって異なります)。
あなたのPHPコードは非常に非効率的です。 (私はPHPを非難しています。PHPの標準ライブラリのため、効率的なコードを書くのは非常に難しいです)。フォルダの4つのレベルより深いものがある場合(実際に何かを書く必要があります)再帰ディレクトリを通してはできません)。
とにかくbash
簡単です。
shopt -s globstar
for file in **/** ; do
echo "${file} found!"
done
ただし、これはPHPでファイルのリストが必要な場合は実際には役に立ちません。ディレクトリを参照するためにワイルドカードは必要ありません。実際、これは明らかに間違ったツールです。 PHPのメソッドを使用してディレクトリを一覧表示し、ディレクトリが見つかるたびに見つけたディレクトリから同じメソッドを呼び出します。
答え2
私はお勧めしますfind
find /folder/ -mindepth 3 -maxdepth 3 -type f
使用するかどうかは処理方法によって-exec
異なります。-execdir
-print0 | xargs -0
find
AFAIKはファイルを検索する最速の方法の1つです。
答え3
1967年以来、コンピュータプログラマとして、小型で低速のコンピュータに接続された小型で低速の機械的に配置されたディスク上のファイルを整列させることが問題であったことを覚えています。進歩はこれらの懸念を取り除きます。より速く、より大きなコンピュータ、より速く、より大きなソフトウェア(RAMのバッファリングによってディスクがRAM速度に近づく)、より速く、より大きく、よりスマートなディスクとディスクに似たオブジェクト、ディスクドライバのさらなる開発...ファイルの実際の場所に興味を持っている人はほとんどいません。ディスクに(C/H/S 意味で)。 「最新」ディスクドライバは、検索時間を最小限に抑えるために要求の順序を変更し、何十年もこれを行ってきました。
ファイル名のリストを生成するのは難しいです。最初は何百万もの名前はすべて必要ありません。
find
(読み取り - 繰り返し - 読み取り)を使用するman find
か、独自のディレクトリナビゲーションコードを回転させます。
「ディレクトリ」は、d------
権限にビットが設定されたファイルです。
これには、ファイルまたはディレクトリへのポインタが含まれます。
readdir
合理的なプログラミング言語を使用すると、インターフェース()にアクセスできますman readdir
。
答え4
私の質問を再現しましょう。入れ子になったフォルダ(ext4を含むHDD)に保存されている何百万ものファイルの内容を読み取る最速の方法は何ですか?
ファイルシステムが提供するものよりも良い順序はありません。
特定の順序でソートされたファイル(ハードドライブセクタに保存)
ファイルがディスク上で何らかの方法で「ソート」され、パスによって異なると仮定します。しかし、実際にはそうではありません。
ファイルシステム、特にext2/3/4にはファイル記述を含むディスクレイアウトがあります(ディレクトリは実際には他のファイルのリストを指すいくつかの特殊ファイルのみです)、これらの説明にはファイル名とデータを格納するブロック/ブロックが含まれていますになります。ファイル範囲のリスト(ファイルがメタデータを保存するのに十分短くない場合)
今、これらのファイルは通常いいえそのパスが何らかの方法で関連付けられている場合は、ディスクから連続しています。このようなことは起こりません。可能であれば、新しいファイルデータの空き領域が選択されます。さらに、単一ファイル自体は連続的であるという保証はありません!データが格納されるブロックが順番にある必要はありません。
だからあなたは本当にできないユーザーの視点でより速くする:ファイルシステムを使用する目的は、ファイルを使用するプログラムでファイルがすべて記憶媒体のブロックであるという事実を隠すことです。
あなたができる最善はいいえファイルを並べ替えます。システムコールと対話すると、ファイルシステムからファイルをインポートする順序がreaddir
異なる可能性があります(プログラミング言語が何であれ、ファイルシステムにファイルリストを要求する方法があります)。スペースが割り当てられる順序では、順序はブロックとinodeマッピングの順序であり、ディスクの順序とある程度一致することができます。
さらに重要なのは、シングルスレッド(SSDにアクセスできる場合はこれを実行しないでください)と、ファイルシステムでHDDに対してナビゲーション時間を集中的に実行しようとしているという事実に根本的に制限があることです。このクラスは最適化されたアクセスを提供します。いいえこれを行うには、良い古典的なファイルシステムを見つけてください。これは、古典的なファイルシステムがうまくいくはずではないからです。
したがって、構造的にアプローチを改善することができます(私が言うPHPコードが非効率的であることはまさにこれであるという意味です)。
後でなくファイルが見つかった場合は、ファイルの内容を読み込みます。メタデータはファイルデータと同じようにディスクに配布されるため、ディレクトリ内のファイルのリストを読み取るために別の場所にジャンプするために、ファイルの内容を読み取るのと同じナビゲーション時間があります。したがって、「ファイルのリストをインポートして各ファイルを読み取る」の代わりに、次の手順を実行します。
- ディレクトリの最初の項目を取得する
- ファイルの場合は読み取りを開始します
(つまり、open
ING- キューにファイル記述子を追加します。
- キューを読み取る別のスレッドで
- そこで現在処理中のファイル数を追跡し、
- 合理的なしきい値より低い場合は、キューの終わりをポップして、
fadvise
ファイル全体を読みたいのですが、- イベントにファイル記述子を追加
epoll
し、 - 別の脅威では
epoll_wait
。
ディスクをアイドル状態にしないでください。カーネルがバッファを完全に活用する機会を提供するので、ディスク上の同じ場所を2回見つける必要はありません。
ディレクトリの場合は、そのディレクトリの1に移動します。- 次のディレクトリに移動します。
ファイルシステムバッファが十分に大きいことを確認してください。すべてのファイルシステムメタデータをキャッシュできるようにしたいです。最新のLinuxシステムでは、十分なRAMを提供する以外に多くの作業を行う必要はありません。
感染症のようなPHPのような言語を避けてください(システムコールによって完全に異なる場所を見ることができ、これが最初のパフォーマンスの問題である場合、以下でどのシステムコールが実行されるのかわかりにくくなります)(また、感染症を避けてください)PHPのような言語では)コードの部分があまりにも美しく説明されているように、間違った言語デザインの典型です! )
この作業を複数回実行する必要がある場合は、
cp -ar
データを新しいファイルシステムに移動することを少し考えてください(おそらく外部4しかし、FS Markやその他の包括的な「多くのファイル処理」の問題にはうまく機能します。これにより、ディレクトリエントリが作成(コピー)の順序で指定され、ファイル名の順序によって実際に何かがある可能性が高くなります。ディスクストレージを使用します。それでも保証はありません!
読み取り専用の場合は、特定の順序を保証するいくつかの方法があります。読み取り専用ファイルシステムに入れます(私は圧縮するsquashfsが好きです。本物思ったよりも重要です。)そのファイルシステムを他のファイルシステムではなくディスクに保存してください。本当にファイルアクセスが必要かどうかを検討してください。ファイルシステムは本当にあなたが持っている情報を保存する正しい方法ですか?それともリレーショナルデータベース(sqlite?Postgresql?)か、ドキュメント指向のデータベースですか?