Чому "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. Як оболонка, обробка великого вектора аргументів, так і lss, ймовірно, буде мати багато виділення в пам'яті невеликих блоків, що може зайняти деякий час. Однак, так як там було мало sysі userчасу, але багато realчасу, більшу частину часу були б витрачені в очікуванні диска, а не з допомогою процесора робить виділення пам'яті.

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

Різниця між шаблоном підстановки та ls -l50% може бути пояснена впорядкуванням входів на диску. Якби вставки були викладені послідовно в тому ж порядку, як імена файлів у каталозі та 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ним можна просто запитати у файловій системі "для чого діти вводу pwd", де як з ls *він повинен запитати "які діти (і який файл) inode a", а потім b, c, d тощо. Один запит проти багатьох.
NJ

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

@Sebastian Як зазначає Кемх, для отримання інформації про часові позначки / інформацію про власників / дозволи та ін. ls -lБуде потрібно довше, ніж lsце потрібно stat(2),
NJ

6
Не забувайте, *глобуси для всіх записів у поточному каталозі, які не починаються з періоду, включаючи назви підкаталогів. Що потім буде lsвидано.
Шадур

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