Por que "ls *" demora tanto mais que "ls"?


28

Eu tenho alguns arquivos em um diretório:

$ ls | wc -l
9376

Alguém pode explicar por que existe uma diferença de horário tão grande no uso ls *e ls?

$ time ls > /dev/null
real    0m0.118s
user    0m0.106s
sys     0m0.011s

e

$ time ls * > /dev/null
real    1m32.602s
user    0m0.233s
sys     0m0.438s

ok, este é um exemplo drástico e talvez aprimorado porque o diretório está em um sistema geral de arquivos paralelos (GPFS). Mas também vejo uma desaceleração significativa em um sistema de arquivos local.

EDITAR:

$ time ls -l > /dev/null
real    0m58.772s
user    0m0.113s
sys     0m0.452s
$ time ls -l * > /dev/null
real    1m19.538s
user    0m0.252s
sys     0m0.461s

e devo acrescentar que no meu exemplo não há subdiretórios:

$ diff <(ls) <(ls *)
$

Respostas:


47

Quando você executa lssem argumentos, ele abre apenas um diretório, lê todo o conteúdo, classifica e imprime.

Quando você executa ls *, primeiro o shell se expande *, o que é efetivamente o mesmo que o simples ls, cria um vetor de argumento com todos os arquivos no diretório e chamadas atuais ls. lsdepois, processa esse vetor de argumento e para cada argumento e chama access(2)o arquivo para verificar sua existência. Em seguida, imprimirá a mesma saída que a primeira (simples) ls. O processamento do vetor de argumento grande e do shell lsprovavelmente envolverá muita alocação de memória de pequenos blocos, o que pode levar algum tempo. No entanto, como havia pouco syse usertempo, mas muito realtempo, a maior parte do tempo seria gasta aguardando disco, em vez de usar a CPU para alocar memória.

Cada chamada para access(2)precisará ler o inode do arquivo para obter as informações de permissão. Isso significa muito mais leituras e buscas em disco do que simplesmente ler um diretório. Não sei quão caras essas operações são no seu GPFS, mas como a comparação que você mostrou com ls -lum tempo de execução semelhante ao caso curinga, o tempo necessário para recuperar as informações do inode parece dominar. Se o GPFS tiver uma latência um pouco mais alta que o sistema de arquivos local em cada operação de leitura, esperamos que seja mais pronunciado nesses casos.

A diferença entre o caso curinga e ls -l50% pode ser explicada pela ordem dos inodes no disco. Se os inodes fossem dispostos sucessivamente na mesma ordem que os nomes dos arquivos no diretório e ls -lstat (2) editas os arquivos na ordem dos diretórios antes da classificação, ls -lpossivelmente leriam a maioria dos inodes em uma varredura. Com o curinga, o shell classificará os nomes dos arquivos antes de passá-los para ls, portanto ls, provavelmente lerá os inodes em uma ordem diferente, adicionando mais movimento da cabeça do disco.

Note-se que sua timesaída não incluirá o tempo gasto pelo shell para expandir o curinga.

Se você realmente deseja ver o que está acontecendo, use strace(1):

strace -o /tmp/ls-star.trace ls *
strace -o /tmp/ls-l-star.trace ls -l *

e veja quais chamadas do sistema estão sendo executadas em cada caso.

¹ Não sei se access(2)é realmente usado ou algo mais como stat(2). Mas ambos provavelmente exigem uma pesquisa de inode (não tenho certeza se access(file, 0)ignoraria uma pesquisa de inode.)


2
Boa resposta, eu estava prestes a postar uma semelhante :) Mas sim, isso está correto, é tudo sobre eficiência no loop, com lsele pode apenas perguntar ao sistema de arquivos "para que servem os filhos do inode pwd" ls *ele deve perguntar "quais são os filhos (e qual é o arquivo) do inode a" seguido de b, c, d, etc. etc. Uma consulta versus muitas.
NJ

@NJ uma consulta vs muitos é um bom resumo até agora. @ camh: obrigado pela resposta detalhada. Eu postei a saída do ls -lbem (ainda cerca de 30 segundos a menos de ls *)
Sebastian

@Sebastian Como CAMH afirmou, ls -lvai demorar mais do que lsuma vez que tem para stat(2)cada arquivo para obter informações sobre marcas de tempo / informações do proprietário / permissões, etc.
NJ

6
Não se esqueça, *globs para todas as entradas no diretório atual que não começam com um período - incluindo os nomes dos subdiretórios. Que será então lsed.
Shadur 5/05

@camh: Eu testei um pouco mais (ver as minhas edições) e constatou que: ls< ls -l< ls -l *< ls *(eu sempre corri três vezes). Com a sua explicação, eu não entendo porque ls -l *é mais rápido quels *
Sebastian
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.