ls
na verdade classifica os arquivos e tenta listá-los, o que se torna uma enorme sobrecarga se estivermos tentando listar mais de um milhão de arquivos dentro de um diretório. Como mencionado em este link , podemos use strace
ou find
para listar os arquivos. No entanto, essas opções também pareciam inviáveis para o meu problema, pois eu tinha 5 milhões de arquivos. Depois de um pouco de googling, descobri que se listarmos os diretórios usando getdents()
, é suposto ser mais rápido, porque as bibliotecas ls
, find
e Python
usam readdir()
, que é mais lento, mas usa getdents()
por baixo.
Podemos encontrar o código C para listar os arquivos usando getdents()
de aqui :
/*
* 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 o programa C acima no diretório em que os arquivos precisam ser listados. Em seguida, execute os comandos abaixo.
gcc getdents.c -o getdents
./getdents
Exemplo de intervalos : getdents
pode ser muito mais rápido que ls -f
, dependendo da configuração do sistema. Aqui estão alguns tempos demonstrando um aumento de velocidade de 40x para listar um diretório contendo cerca de 500k arquivos em uma montagem NFS em um cluster de computação. Cada comando foi executado 10 vezes em sucessão imediata, primeiro getdents
e, em seguida, ls -f
. A primeira execução é significativamente mais lenta que todas as outras, provavelmente devido a falhas de página de cache do NFS. (Além: sobre essa montagem, o campo d_type
não é confiável, no sentido de que muitos arquivos aparecem como tipo "desconhecido".)
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%