web-dev-qa-db-ja.com

「ls *」が「ls」よりもはるかに長いのはなぜですか?

ディレクトリにいくつかのファイルがあります:

$ ls | wc -l
9376

誰かがls *lsの使用にこんなに大きな時差がある理由を説明できますか?

$ time ls > /dev/null
real    0m0.118s
user    0m0.106s
sys     0m0.011s

そして

$ time ls * > /dev/null
real    1m32.602s
user    0m0.233s
sys     0m0.438s

わかりました。これは抜本的な例であり、ディレクトリが一般的な並列ファイルシステム(GPFS)上にあるため、拡張される可能性があります。しかし、ローカルファイルシステムでも大幅な速度低下が見られます。

編集:

$ time ls -l > /dev/null
real    0m58.772s
user    0m0.113s
sys     0m0.452s
$ time ls -l * > /dev/null
real    1m19.538s
user    0m0.252s
sys     0m0.461s

私の例ではサブディレクトリがないことを追加する必要があります:

$ diff <(ls) <(ls *)
$
28
Sebastian

lsを引数なしで実行すると、ディレクトリが開かれ、すべての内容が読み取られ、並べ替えられて出力されます。

_ls *_を実行すると、最初にシェルが_*_を展開します。これは、単純なlsと実質的に同じであり、現在のディレクトリ内のすべてのファイルを含む引数ベクトルを作成して呼び出します。 ls。次に、lsはその引数ベクトルと各引数を処理し、ファイルの存在を確認するためにaccess(2)]を呼び出します。次に、最初の(単純な)lsと同じ出力を出力します。シェルによる大きな引数ベクトルの処理とlsの処理の両方で、小さなブロックの大量のメモリ割り当てが必要になる可能性があり、時間がかかる場合があります。ただし、sysuserの時間はほとんどなかったが、realの時間が長いため、CPUを使用するのではなく、ほとんどの時間がディスクの待機に費やされていました。メモリ割り当て。

access(2)を呼び出すたびに、許可情報を取得するためにファイルのiノードを読み取る必要があります。つまり、単にディレクトリを読み取るよりも多くのディスクの読み取りとシークを行います。私のGPFSでこれらの操作がどれほどコストがかかるかはわかりませんが、ワイルドカードの場合と同様の実行時間を持つ_ls -l_と比較すると、inode情報の取得に必要な時間が圧倒的に多いようです。 GPFSが各読み取り操作でローカルファイルシステムよりもわずかに高いレイテンシを持っている場合、これらのケースではそれがより顕著になると予想されます。

ワイルドカードと50%の_ls -l_の違いは、ディスク上のiノードの順序で説明できます。 iノードがディレクトリ内のファイル名と同じ順序で連続してレイアウトされ、ソート前に_ls -l_ stat(2)でファイルがディレクトリ順に並べられた場合、_ls -l_は、掃く。ワイルドカードを使用すると、シェルはファイル名をlsに渡す前にソートするため、lsはiノードを別の順序で読み取る可能性が高く、ディスクヘッドの動きが増えます。

timeの出力には、シェルがワイルドカードを展開するのにかかった時間は含まれないことに注意してください。

本当に何が起こっているのかを見たい場合は、strace(1)を使用してください:

_strace -o /tmp/ls-star.trace ls *
strace -o /tmp/ls-l-star.trace ls -l *
_

それぞれのケースで実行されているシステムコールを確認してください。

access(2)が実際に使用されているのか、それともstat(2)などが使用されているのかはわかりません。しかし、両方ともおそらくiノードルックアップが必要です(access(file, 0)がiノードルックアップをバイパスするかどうかはわかりません)。

47
camh