Более быстрый способ каталогов, идущий вместо 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) 

В моем случае, который менял разрешения на тысячи файлов, это работало намного лучше.