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

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

$ 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). Но я также вижу значительное замедление в локальной файловой системе.

EDIT:

$ 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 *)
$
28 голосов | спросил Sebastian 5 Mayam11 2011, 10:57:05

1 ответ


47

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

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

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

Разность между шаблоном и ls -l из 50% может быть объяснена упорядочением inodes на диске. Если индексы были последовательно размещены в том же порядке, что и имена файлов в каталоге, а ls -l stat (2) отредактировали файлы в каталоге перед сортировкой ls -l, возможно, прочитает большую часть inodes в развертке. С помощью шаблона оболочка будет сортировать имена файлов, прежде чем передавать их в 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.)

ответил camh 5 Mayam11 2011, 11:14:47

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132