ls
en realidad clasifica los archivos e intenta enumerarlos, lo que se convierte en una gran sobrecarga si estamos tratando de enumerar más de un millón de archivos dentro de un directorio. Como se menciona en este enlace, podemos usar strace
o find
para enumerar los archivos. Sin embargo, esas opciones también parecían inviables para mi problema ya que tenía 5 millones de archivos. Después de algún poco de google, he encontrado que si enumeramos los directorios usando getdents()
, se supone que es más rápido, porque ls
, find
y Python
las bibliotecas utilizan readdir()
que es más lento pero utiliza getdents()
debajo.
Podemos encontrar el código C para enumerar los archivos usando getdents()
desde aquí :
/*
* 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);
}
Copie el programa C anterior en el directorio en el que deben enumerarse los archivos. Luego ejecute los siguientes comandos.
gcc getdents.c -o getdents
./getdents
Ejemplo de tiempos : getdents
puede ser mucho más rápido que ls -f
, dependiendo de la configuración del sistema. Aquí hay algunos tiempos que demuestran un aumento de velocidad de 40x para listar un directorio que contiene aproximadamente 500k archivos sobre un montaje NFS en un clúster de cómputo. Cada comando se ejecutó 10 veces en sucesión inmediata, primero getdents
, luego ls -f
. La primera ejecución es significativamente más lenta que todas las demás, probablemente debido a fallas en la página de almacenamiento en caché NFS. (Aparte: sobre este montaje, el d_type
campo no es confiable, en el sentido de que muchos archivos aparecen como tipo "desconocido").
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
esos usos--color
o-F
como eso significaría hacer unlstat(2)
para cada archivo.