ls
sortiert die Dateien tatsächlich und versucht, sie aufzulisten, was zu einem enormen Overhead wird, wenn wir versuchen, mehr als eine Million Dateien in einem Verzeichnis aufzulisten. Wie in diesem Link erwähnt, können wir die Dateien mit strace
oder find
auflisten. Diese Optionen schienen jedoch auch für mein Problem nicht realisierbar zu sein, da ich 5 Millionen Dateien hatte. Nach einiger bisschen googeln, fand ich , dass , wenn wir die Verzeichnisse mit der Anwendung getdents()
wird angenommen , schneller zu sein, weil ls
, find
und Python
Bibliotheken verwenden , readdir()
die langsamer ist, verwendet aber getdents()
darunter.
Wir können den C - Code finden Sie die Dateien mit zur Liste getdents()
von hier :
/*
* 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);
}
Kopieren Sie das obige C-Programm in das Verzeichnis, in dem die Dateien aufgelistet werden müssen. Führen Sie dann die folgenden Befehle aus.
gcc getdents.c -o getdents
./getdents
Beispiel für Timings : getdents
Kann ls -f
je nach Systemkonfiguration viel schneller sein als . Im Folgenden sind einige Zeitangaben aufgeführt, die eine 40-fache Geschwindigkeitssteigerung beim Auflisten eines Verzeichnisses mit ca. 500.000 Dateien über einen NFS-Mount in einem Compute-Cluster demonstrieren. Jeder Befehl wurde 10 Mal unmittelbar nacheinander ausgeführt werden , zuerst getdents
, dann ls -f
. Die erste Ausführung ist bedeutend langsamer als alle anderen, wahrscheinlich aufgrund von Fehlern bei der NFS-Caching-Seite. (Abgesehen davon: Über diesen Mount ist das d_type
Feld unzuverlässig, da viele Dateien als "unbekannter" Typ angezeigt werden.)
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
das verwendet--color
oder-F
als das würde bedeuten, ein tunlstat(2)
für jede Datei.