約500万のファイルがあるディレクトリがありました。ls
このディレクトリ内からコマンドを実行しようとすると、システムが大量のメモリを消費し、しばらくしてハングしました。ls
コマンドを使用する以外にファイルをリストする効率的な方法はありますか?
ls
電話でしたか、それともオプションを使用しましたか?
約500万のファイルがあるディレクトリがありました。ls
このディレクトリ内からコマンドを実行しようとすると、システムが大量のメモリを消費し、しばらくしてハングしました。ls
コマンドを使用する以外にファイルをリストする効率的な方法はありますか?
ls
電話でしたか、それともオプションを使用しましたか?
回答:
以下を使用してソートを回避します。
ls --sort=none # "do not sort; list entries in directory order"
または、同等に:
ls -U
-1
フラグを追加すると役立ちます。
-1
もっと時間がかかるようです。
-C
stdoutが端末の-1
場合、パイプの場合)は混乱を招きます。実験と測定を行うときは、出力の表示(コマンドが期待どおりに動作していることを確認するため)と出力の抑制(端末アプリケーションのスループットの交絡要因を回避するため)を切り替えます。より良いので、明示的に介して出力フォーマットを定義し、両方のモードで同じように動作するコマンドを使用するには-1
、-C
、-l
、など
ls
実際にファイルを並べ替えて一覧表示しようとしますが、ディレクトリ内に100万を超えるファイルを一覧表示しようとすると、大きなオーバーヘッドになります。このリンクで述べたように、strace
またはfind
を使用してファイルをリストできます。ただし、これらのオプションは500万のファイルがあったため、私の問題には実行不可能だと思われました。グーグルのいくつかのビットの後、私たちは使用してディレクトリをリスト場合ことがわかったgetdents()
ので、より高速なことになっているls
、find
とPython
ライブラリが使用readdir()
遅くなりますが、使用するgetdents()
の下に。
ここgetdents()
からファイルをリストするCコードを見つけることができます:
/*
* List directories using getdents() because ls, find and Python libraries
* use readdir() which is slower (but uses getdents() underneath.
*
* Compile with
* ]$ gcc getdents.c -o getdents
*/
#define _GNU_SOURCE
#include <dirent.h> /* Defines DT_* constants */
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#define handle_error(msg) \
do { perror(msg); exit(EXIT_FAILURE); } while (0)
struct linux_dirent {
long d_ino;
off_t d_off;
unsigned short d_reclen;
char d_name[];
};
#define BUF_SIZE 1024*1024*5
int
main(int argc, char *argv[])
{
int fd, nread;
char buf[BUF_SIZE];
struct linux_dirent *d;
int bpos;
char d_type;
fd = open(argc > 1 ? argv[1] : ".", O_RDONLY | O_DIRECTORY);
if (fd == -1)
handle_error("open");
for ( ; ; ) {
nread = syscall(SYS_getdents, fd, buf, BUF_SIZE);
if (nread == -1)
handle_error("getdents");
if (nread == 0)
break;
for (bpos = 0; bpos < nread;) {
d = (struct linux_dirent *) (buf + bpos);
d_type = *(buf + bpos + d->d_reclen - 1);
if( d->d_ino != 0 && d_type == DT_REG ) {
printf("%s\n", (char *)d->d_name );
}
bpos += d->d_reclen;
}
}
exit(EXIT_SUCCESS);
}
上記のCプログラムを、ファイルをリストする必要があるディレクトリにコピーします。次に、以下のコマンドを実行します。
gcc getdents.c -o getdents
./getdents
タイミングの例:システム構成によっては、getdents
よりもはるかに高速になりls -f
ます。以下に、計算クラスタのNFSマウントで約50万のファイルを含むディレクトリをリストするための40倍の速度向上を示すタイミングを示します。各コマンドはまず、即時に連続して10回実行されたgetdents
後、ls -f
。おそらくNFSキャッシュページフォールトが原因で、最初の実行は他のすべての実行よりも大幅に遅くなります。(さておき:このマウントではd_type
、多くのファイルが「不明」タイプとして表示されるという意味で、フィールドは信頼できません。)
command: getdents $bigdir
usr:0.08 sys:0.96 wall:280.79 CPU:0%
usr:0.06 sys:0.18 wall:0.25 CPU:97%
usr:0.05 sys:0.16 wall:0.21 CPU:99%
usr:0.04 sys:0.18 wall:0.23 CPU:98%
usr:0.05 sys:0.20 wall:0.26 CPU:99%
usr:0.04 sys:0.18 wall:0.22 CPU:99%
usr:0.04 sys:0.17 wall:0.22 CPU:99%
usr:0.04 sys:0.20 wall:0.25 CPU:99%
usr:0.06 sys:0.18 wall:0.25 CPU:98%
usr:0.06 sys:0.18 wall:0.25 CPU:98%
command: /bin/ls -f $bigdir
usr:0.53 sys:8.39 wall:8.97 CPU:99%
usr:0.53 sys:7.65 wall:8.20 CPU:99%
usr:0.44 sys:7.91 wall:8.36 CPU:99%
usr:0.50 sys:8.00 wall:8.51 CPU:100%
usr:0.41 sys:7.73 wall:8.15 CPU:99%
usr:0.47 sys:8.84 wall:9.32 CPU:99%
usr:0.57 sys:9.78 wall:10.36 CPU:99%
usr:0.53 sys:10.75 wall:11.29 CPU:99%
usr:0.46 sys:8.76 wall:9.25 CPU:99%
usr:0.50 sys:8.58 wall:9.13 CPU:99%
ls
か?
getdents
対vs についてのこのすべての話readdir
は、ポイントを逃しています。
遅い理由として最も可能性が高いのはファイルタイプの色付けです。色のオプションを使用する\ls
か/bin/ls
、オフにすることでこれを回避できます。
本当に多くのファイルがディレクトリにある場合、find
代わりに使用することも良いオプションです。
ls -U --color
ので時間がかかりstat
ます。両方とも正しいです。
ls
多く.bashrc
の場合、デフォルトでエイリアスされます。
/bin/ls -U
し、時間がないの出力を持って、前に非常に長い時間を待っているに比べて
これecho *
はlsよりもはるかに高速に動作します。YMMV。
*
ます。したがって、この方法は、おそらく500万のファイルに対して非常に遅いです。
ls
ているが、使用--color
または-F
そのようやっ意味しますlstat(2)
ファイルごとに。