¿Por qué "ls *" tarda mucho más que "ls"?


28

Tengo un par de archivos en un directorio:

$ ls | wc -l
9376

¿Alguien puede explicar por qué hay una diferencia de tiempo tan grande al usar ls *y ls?

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

y

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

bueno, este es un ejemplo drástico y tal vez mejorado porque el directorio está en un sistema de archivos paralelo general (GPFS). Pero también puedo ver una desaceleración significativa en un sistema de archivos 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

y debo agregar que en mi ejemplo no hay subdirectorios:

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

Respuestas:


47

Cuando se ejecuta lssin argumentos, solo abrirá un directorio, leerá todo el contenido, los ordenará e imprimirá.

Cuando ejecuta ls *, primero el shell se expande *, que es efectivamente lo mismo que lo que hizo el simple ls, construye un vector de argumento con todos los archivos en el directorio actual y las llamadas ls. lsluego tiene que procesar ese vector de argumento y para cada argumento, y llama access(2)¹ al archivo para verificar su existencia. Luego imprimirá el mismo resultado que el primero (simple) ls. Es lsprobable que tanto el procesamiento de shell del vector de argumento grande como el de s impliquen una gran asignación de memoria de bloques pequeños, lo que puede llevar algún tiempo. Sin embargo, dado que había poco sysy usertiempo, pero mucho realtiempo, la mayor parte del tiempo se hubiera pasado esperando el disco, en lugar de usar la CPU para asignar la memoria.

Cada llamada a access(2)tendrá que leer el inodo del archivo para obtener la información del permiso. Eso significa muchas más lecturas y búsquedas de disco que simplemente leer un directorio. No sé qué tan caras son estas operaciones en su GPFS, pero como la comparación que ha demostrado ls -lque tiene un tiempo de ejecución similar al del comodín, parece dominar el tiempo necesario para recuperar la información del inodo. Si GPFS tiene una latencia ligeramente mayor que su sistema de archivos local en cada operación de lectura, esperaríamos que sea más pronunciada en estos casos.

La diferencia entre el caso comodín y el ls -l50% podría explicarse por el pedido de inodos en el disco. Si los inodes se dispusieran sucesivamente en el mismo orden que los nombres de archivo en el directorio y ls -lstat (2) editara los archivos en orden de directorio antes de ordenarlos, ls -lposiblemente leería la mayoría de los inodes en un barrido. Con el comodín, el shell ordenará los nombres de los archivos antes de pasarlos ls, por lslo que probablemente leerá los inodos en un orden diferente, agregando más movimiento de la cabeza del disco.

Cabe señalar que su timesalida no incluirá el tiempo que tarda el shell para expandir el comodín.

Si realmente quieres ver lo que está pasando, usa strace(1):

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

y eche un vistazo a las llamadas del sistema que se realizan en cada caso.

¹ No sé si access(2)realmente se usa, o algo más como stat(2). Pero ambos probablemente requieran una búsqueda de inodo (no estoy seguro si access(file, 0)pasarían por alto una búsqueda de inodo).


2
Buena respuesta, estaba a punto de publicar una similar :) Pero sí, esto es correcto, todo se trata de eficiencias en el bucle, con lssolo preguntarle al sistema de archivos "para qué son los hijos del inodo pwd" dónde como con ls *tiene que preguntar "cuáles son los elementos secundarios (y cuál es el archivo) del inodo a" seguido de b, c, d, etc. etc. Una consulta frente a muchas.
NJ

@NJ one query vs many es un buen resumen hasta ahora. @camh: gracias por la respuesta detallada. También publiqué la salida de ls -l(todavía unos 30 segundos menos que ls *)
Sebastian

@Sebastian Como camh indicado, ls -lllevará más tiempo que lscomo lo ha hecho a stat(2)cada archivo para obtener información sobre las marcas de tiempo / información del propietario / permisos, etc.
NJ

66
No olvide, *pasa a todas las entradas del directorio actual que no comienzan con un punto, incluidos los nombres de subdirectorios. Que luego será ls'ed.
Shadur

@camh: Probé un poco más (ver mis ediciones) y se encontró que: ls< ls -l< ls -l *< ls *(siempre me encontré con ella tres veces). Con su explicación, no entiendo por qué ls -l *es más rápido quels *
Sebastian
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.