Почему «ls *» занимает намного больше времени, чем «ls»?


28

У меня есть несколько файлов в каталоге:

$ ls | wc -l
9376

Кто-нибудь может объяснить, почему существует такая огромная разница во времени при использовании ls *и ls?

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

а также

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

хорошо, это радикальный пример и может быть улучшен, потому что каталог находится в общей параллельной файловой системе (GPFS). Но я также вижу значительное замедление в локальной файловой системе.

РЕДАКТИРОВАТЬ:

$ 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

и я должен добавить, что в моем примере нет подкаталогов:

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

Ответы:


47

Когда вы запускаете lsбез аргументов, он просто открывает каталог, читает все содержимое, сортирует их и распечатывает.

Когда вы запускаете ls *, сначала расширяется оболочка *, которая, по сути, такая же, как и простая ls, создает вектор аргумента со всеми файлами в текущем каталоге и вызовами ls. lsзатем должен обработать этот вектор аргумента и для каждого аргумента и access(2)вызвать файл, чтобы проверить его существование. Затем он выведет тот же вывод, что и первый (простой) ls. Обработка оболочкой большого вектора аргумента и аргументов ls, вероятно, потребует большого объема памяти, выделяемой маленьким блокам, что может занять некоторое время. Однако, так как там было мало sysи userвремени, но много realвремени, большую часть времени были бы потрачены в ожидании диска, а не с помощью процессора делает выделение памяти.

Каждый вызов должен access(2)будет прочитать inode файла, чтобы получить информацию о разрешениях. Это означает, что гораздо больше операций чтения и поиска на диске, чем просто чтение каталога. Я не знаю, насколько дорогими являются эти операции в вашей GPFS, но, как показывает сравнение, время выполнения ls -lкоторого аналогично случаю с подстановочными знаками, время, необходимое для получения информации об индексах, кажется доминирующим. Если GPFS имеет немного большую задержку, чем ваша локальная файловая система при каждой операции чтения, мы ожидаем, что она будет более выраженной в этих случаях.

Разницу между регистром подстановки и ls -l50% можно объяснить порядком расположения inode на диске. Если иноды были расположены в том же порядке, что и имена файлов в каталоге, и ls -lstat (2) редактировал файлы в порядке каталога перед сортировкой, ls -lвозможно , будет считано большинство инодов в цикле. Используя подстановочный знак, оболочка будет сортировать имена файлов, прежде чем передавать их ls, поэтому ls, скорее всего, будет читать иноды в другом порядке, добавляя больше движения головки диска.

Следует отметить, что ваши timeвыходные данные не будут включать время, затрачиваемое оболочкой на развертывание подстановочного знака.

Если вы действительно хотите увидеть, что происходит, используйте strace(1):

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

и посмотрите, какие системные вызовы выполняются в каждом случае.

¹ Я не знаю, используется ли access(2)это на самом деле, или что-то еще, например stat(2). Но оба, вероятно, требуют поиска inode (я не уверен, если access(file, 0)бы обойти поиск inode.)


2
Хороший ответ, я как раз собирался опубликовать аналогичный :) Но да, это правильно, все дело в эффективности циклов, с помощью lsкоторой можно просто спросить файловую систему "для чего нужны дочерние узлы inode pwd", где как с ls *он должен спросить «каковы дочерние элементы (и что это за файл) в inode a», а затем b, c, d и т. д. и т. д. Один запрос против многих.
Нью-Джерси

@NJ один запрос против многих - это хорошее резюме. @camh: спасибо за подробный ответ. Я также опубликовал вывод ls -l(все еще примерно на 30 секунд меньше ls *)
Себастьян

@Sebastian Как сказал camh, для получения информации о метках времени / информации о владельце / разрешениях и т. Д. ls -lПотребуется больше времени, чем lsтребуется для stat(2)каждого файла
Нью-Джерси,

6
Не забудьте, *всплывающие окна со всеми записями в текущем каталоге, которые не начинаются с точки, включая имена подкаталогов. Что тогда будет ls« под ред.
Шадур

@camh: Я испытал немного больше (см моих правок) и обнаружил , что: ls< ls -l< ls -l *< ls *(я всегда пытался это трижды). С твоим объяснением я не понимаю, почему ls -l *это быстрее, чемls *
Себастьян
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.