ls
trie réellement les fichiers et essaie de les lister, ce qui devient un lourd fardeau si nous essayons de répertorier plus d’un million de fichiers dans un répertoire. Comme mentionné dans ce lien, nous pouvons utiliser strace
ou find
répertorier les fichiers. Cependant, ces options semblaient également irréalisables pour mon problème puisque j'avais 5 millions de fichiers. Après un peu de recherche sur Google, j'ai trouvé que si nous listons les répertoires en utilisant getdents()
, il est supposé être plus rapide, car ls
, find
et les Python
bibliothèques utilisent readdir()
ce qui est plus lent mais utilise en getdents()
dessous.
Nous pouvons trouver le code C à la liste des fichiers à l' aide getdents()
d' ici :
/*
* 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);
}
Copiez le programme C ci-dessus dans le répertoire dans lequel les fichiers doivent être listés. Puis exécutez les commandes ci-dessous.
gcc getdents.c -o getdents
./getdents
Exemple de minutage : getdents
peut être beaucoup plus rapide que ls -f
, en fonction de la configuration du système. Voici quelques timings démontrant une augmentation de 40 fois la vitesse de création d'un répertoire contenant environ 500 000 fichiers sur un montage NFS dans un cluster de calcul. Chaque commande a été exécutée 10 fois en succession immédiate, d’abord getdents
, puis ls -f
. La première exécution est nettement plus lente que toutes les autres, probablement en raison de défauts de mise en mémoire cache NFS. (En outre: sur ce montage, le d_type
champ n'est pas fiable, en ce sens que de nombreux fichiers apparaissent sous le type "inconnu".)
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
cet usage--color
ou-F
pour signifier que vous feriez unlstat(2)
pour chaque fichier.