Более быстрый способ каталогов, идущий вместо os.listdir?
Я пытаюсь улучшить производительность elfinder, файлового менеджера на основе ajax (elRTE.ru).
Он использует os.listdir в recurisve для рекурсивного просмотра всех каталогов и получения производительности (например, перечисление каталога с 3000 + файлами занимает 7 секунд).
Я пытаюсь улучшить производительность для него, это функция хождения:
for d in os.listdir(path):
pd = os.path.join(path, d)
if os.path.isdir(pd) and not os.path.islink(pd) and self.__isAccepted(d):
tree['dirs'].append(self.__tree(pd))
Мои вопросы:
- Если я изменю os.walk вместо os.listdir, улучшит ли производительность?
- Как насчет использования dircache.listdir()? кешировать содержимое каталога/подкаталога WHOLE в исходном запросе и возвращать результаты кеша, если нет новых файлов, загруженных или никаких изменений в файле?
- Есть ли какой-нибудь другой метод хождения по каталогу, который быстрее?
- Любой другой браузер на стороне сервера, который быстро написан на питоне (но я предпочитаю сделать это быстро)?
Ответы
Ответ 1
Я просто пытался выяснить, как ускорить os.walk на довольно большой файловой системе (350 000 файлов распространяются в пределах около 50 000 каталогов). Я нахожусь в linux box usign файловой системы ext3. Я обнаружил, что есть способ ускорить это для MY case.
В частности, используя прокрутку сверху вниз, любое время os.walk возвращает список из более чем одного каталога, я использую os.stat для получения номера inode каждого каталога и сортировки списка каталогов по номеру inode. Это делает прогулку, главным образом, посещать подкаталоги в порядке inode, что уменьшает количество запросов на поиск.
В моем случае использования он ускорил мой полный ход каталога с 18 минут до 13 минут...
Ответ 2
Вы проверили scandir (ранее betterwalk)? Не пробовал сам, но здесь обсуждение здесь и еще один здесь. Он утверждает, что ускоряет 3 ~ 10x на MacOSX/Linux и 7 ~ 50x на Windows, избегая избыточных вызовов os.stat(). Он также теперь включен в стандартную библиотеку с Python 3.5.
Встроенный os.walk() Python значительно медленнее, чем нужно быть, потому что - в дополнение к вызову listdir() в каждом каталоге - он вызывает stat() для каждого файла, чтобы определить, является ли имя файла или нет. Но и FindFirstFile/FindNextFile для Windows и readdir в Linux/OS X уже говорит вам, вернулись ли файлы каталогов или нет, поэтому не требуется никаких дополнительных системных вызовов. В короткое, вы можете уменьшить количество системных вызовов от примерно 2N до N, где N - общее количество файлов и каталогов в дереве.
На практике удаление всех этих дополнительных системных вызовов делает os.walk() о в 7-50 раз быстрее, чем в Windows, и примерно в 3-10 раз быстрее Linux и Mac OS X.
Из readme.
Ответ 3
Вы должны измерять непосредственно на машинах (ОС, файловых системах и кешках и т.д.) вашего конкретного интереса - будь то os.walk
быстрее, чем os.listdir
на конкретной и полностью другой машине/ОС/FS расскажите вам очень мало о производительности на вашем.
Не уверен, что вы подразумеваете под cachedir.listdir
- нет стандартного библиотечного модуля/функции этим именем. listdir
уже считывает всю директорию в одном gulp (так как он должен сортировать результаты), как и os.walk
(так как он должен разделять подкаталоги из файлов). Если в зависимости от вашей платформы у вас есть быстрый способ получения уведомлений о изменениях файлов/каталогов, то, вероятно, стоит построить дерево один раз и изменить его постепенно, так как появятся уведомления об изменениях... но это зависит от относительной частоты изменений vs запросы, которые, опять же, полностью зависят от ваших конкретных условий приложения.
Ответ 4
В порядке:
-
Я сомневаюсь, что вы увидите большую часть ускорения между os.walk
и os.listdir
, так как оба полагаются на базовую файловую систему. На самом деле, я подозреваю, что базовая файловая система будет иметь большое влияние на скорость работы.
-
Любая операция кеша будет значительно быстрее, чем ударить файловую систему (по крайней мере, для второй и последующих проверок).
-
Вы всегда можете написать какую-нибудь утилиту (или вызвать команду оболочки), которая генерирует список каталогов за пределами Python и вызывается через модуль subprocess
. Но это немного сложно, и я обращусь к этому решению только в том случае, если кэш не работает для вас.
-
Если вы не обнаружили файловый браузер на Cheeseshop, вы, вероятно, его не найдете.
Ответ 5
Вы ищете fsdir. Он написан на языке C и предназначен для работы с python. Это намного быстрее, чем ходить по дереву со стандартными библиотеками python.
Ответ 6
os.path.walk
может увеличить вашу производительность по двум причинам:
1) Если вы можете остановить ходьбу, прежде чем вы пройдете все, то это будет быстрее, чем listdir
, хотя это заметно только при работе с большими деревьями
2) Если вы указываете ОГРОМНЫЕ каталоги, то может быть дорого сделать список, возвращаемый listdir
. (Не верно, см. Комментарий alex ниже)
Однако, вероятно, это не повлияет и может быть на самом деле медленнее из-за потенциально дополнительных накладных расходов, вызванных вызовом вашей функции visit
и выполнением всех дополнительных аргументов упаковки и распаковки.
(На самом деле единственный способ ответить на этот вопрос - проверить его самостоятельно - это займет всего несколько минут)
Ответ 7
Как это сделать в bash?
import subprocess
command = 'ls .... or something else'
subprocess.Popen([command] ,shell=True)
В моем случае, который менял разрешения на тысячи файлов, это работало намного лучше.