ディレクトリにいくつかのファイルがあります:
$ 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 *)
$
ls
を引数なしで実行すると、ディレクトリが開かれ、すべての内容が読み取られ、並べ替えられて出力されます。
_ls *
_を実行すると、最初にシェルが_*
_を展開します。これは、単純なls
と実質的に同じであり、現在のディレクトリ内のすべてのファイルを含む引数ベクトルを作成して呼び出します。 ls
。次に、ls
はその引数ベクトルと各引数を処理し、ファイルの存在を確認するためにaccess(2)
]を呼び出します。次に、最初の(単純な)ls
と同じ出力を出力します。シェルによる大きな引数ベクトルの処理とls
の処理の両方で、小さなブロックの大量のメモリ割り当てが必要になる可能性があり、時間がかかる場合があります。ただし、sys
とuser
の時間はほとんどなかったが、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ノードルックアップをバイパスするかどうかはわかりません)。