「ls *」が「ls」よりもずっと長くかかるのはなぜですか?


28

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

$ ls | wc -l
9376

ls *and を使用するのになぜこんなに大きな時間差があるのか​​、誰でも説明できます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 *)
$

回答:


47

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

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

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

ワイルドカードの場合とls -l50%の違いは、ディスク上のiノードの順序によって説明できます。iノードがディレクトリ内のファイル名と同じ順序で連続して配置され、ls -lソートする前にファイルをディレクトリ順にstat(2)したls -l場合、ほとんどのiノードがスイープで読み取られる可能性があります。ワイルドカードを使用すると、シェルはファイル名をに渡す前にソートする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ノード検索を必要とします(iノード検索access(file, 0)をバイパスするかどうかはわかりません)。


2
良い答え、私はちょうど約同様のものを投稿することでした:)しかし、ええ、これは正しいですが、それは、ループ内の効率性についてのすべてですls、それは単に「のiノードの子何のファイルシステムを頼むことができるpwdと同様に」ls *「iノードの子(およびファイル)とは何かa」に続いてb、c、dなどを尋ねる必要があります。1つのクエリと多くのクエリ。
ニュージャージー州

これまでのところ、@ NJの1つのクエリと多くのクエリは良い要約です。@camh:詳細な回答をありがとう。出力も投稿しましたls -l(まだ約30秒未満ls *
セバスチャン

@Sebastian CAMH述べたが、通りls -lよりも長くかかりますlsそれが持っているとしてstat(2)など、タイムスタンプ/所有者情報/アクセス権に関する情報を取得するために、各ファイル
NJ

6
サブディレクトリの名前を含む、ピリオドで始まらない現在のディレクトリ内のすべてのエントリ*へのグロブを忘れないでください。それはそれから編集されます。ls
シャドゥール

@camh:私は(私の編集を参照)もう少しテストし、それを見つけた:ls< ls -l< ls -l *< ls *(私はいつもそれを3回走りました)。あなたの説明では、なぜ私はls -l *ls *
セバスチャン
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.