Более быстрый способ ходьбы по каталогу вместо ОС.listdir?
Я пытаюсь улучшить производительность elFinder, файлового менеджера на основе ajax(elRTE.ru) .
Он использует ОС.listdir в рекурсиве, чтобы пройти через все каталоги рекурсивно и иметь хит производительности (например, перечисление dir с 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))
мои вопросы :
- если я поменяю ОС.ходить вместо ОС.listdir , это повысить производительность?
- как насчет использования dircache.listdir() ? кэшировать все содержимое каталога / субдира по первоначальному запросу и возвращать результаты кэша, если нет новых загруженных файлов или изменений в файле?
- есть ли другой способ ходьбы по каталогу, который быстрее?
- любой другой серверный файловый браузер, который быстро написан на python (но я предпочитаю делать это быстро)?
7 ответов
Я просто пытался выяснить, как ускорить работу ОС.прогулка по большой файловой системе (350 000 файлов, разбросанных в пределах 50 000 каталогов). Я нахожусь в Linux box usign файловой системы ext3. Я обнаружил, что есть способ ускорить это для моего случая.
в частности, с помощью прогулки сверху вниз, в любое время ОС.walk возвращает список из нескольких каталогов, я использую ОС.stat, чтобы получить номер индекса каждого каталога и отсортировать список каталогов по номеру индекса. Это заставляет ходить в основном посетите подкаталоги в порядке inode, что уменьшает поиск диска.
для моего случая использования он ускорил мою полную прогулку по каталогу с 18 минут до 13 минут...
вы проверить scandir (ранее betterwalk)? Сам не пробовал, но есть дискуссия об этом здесь и здесь. Он утверждает, что имеет ускорение 3~10x на MacOSX / Linux и 7~50x на Windows, избегая избыточных вызовов ОС.стат.)( Он также теперь включен в стандартную библиотеку с Python 3.5.
в Python встроенные в ОС.walk() значительно медленнее, чем это необходимо быть, потому что -- в дополнение к вызову listdir() в каждом каталоге -- он вызывает stat () для каждого файла, чтобы определить, является ли имя файла каталог или нет. Но оба FindFirstFile / FindNextFile в Windows и readdir в Linux / OS X уже сообщает вам, возвращаются ли файлы каталоги или нет, поэтому дальнейшие системные вызовы stat не требуются. В короче говоря, вы можете уменьшить количество системных вызовов примерно с 2N до N, где N-общее число файлов и каталогов в дереве.
на практике удаление всех этих дополнительных системных вызовов делает ОС.ходить() о 7-50 раз как быстро на окнах, и около 3-10 раз как быстро дальше Linux и Mac OS X.
вы должны измерять непосредственно на машинах (OSs, файловых системах и их кэшах и т. д.) вашего конкретного интереса-будь то os.walk
быстрее os.listdir
на конкретной и совершенно другой машине / OS / FS расскажет вам очень мало о производительности на твой.
не уверен, что вы подразумеваете под cachedir.listdir
-- нет стандартного библиотечного модуля / функции с этим именем. listdir
уже читает весь каталог одним глотком (так как он должен сортировать результаты), как это делает os.walk
(Так как он должен отделять подкаталоги от файлов). Если, в зависимости от вашей платформы, у вас есть быстрый способ получать уведомления об изменениях файлов/каталогов, то, вероятно, стоит построить дерево один раз и редактировать его постепенно по мере поступления уведомлений об изменениях... но это зависит от относительной частоты изменений vs запросов, которая, опять же, полностью зависит от код конкретных условий применения.
по порядку:
Я сомневаюсь, что вы увидите большую скорость между
os.walk
иos.listdir
, так как оба полагаются на базовую файловую систему. На самом деле, я подозреваю, что файловой системе будет иметь большое влияние на скорость работы.любая операция кэша будет значительно быстрее, чем попадание в файловую систему (по крайней мере, для второй и последующих проверок).
вы всегда можете написать некоторая утилита( или вызов команды оболочки), которая генерирует список каталогов за пределами Python и вызывает это через
subprocess
модуль. Но это немного сложно, и я бы обратился к этому решению только в том случае, если кэш не сработает для вас.Если вы не нашли файловый браузер на в Cheeseshop, вы, вероятно, не найти.
Как это сделать в bash?
import subprocess
command = 'ls .... or something else'
subprocess.Popen([command] ,shell=True)
в моем случае, который менял разрешения на тысячи файлов, это работало намного лучше.
вы ищете fsdir. Он написан на C и предназначен для работы с python. Это много быстрее, чем ходить по дереву со стандартными библиотеками python.
os.path.walk
мая увеличьте производительность по двум причинам:
1) Если вы можете остановить ходьбу, прежде чем вы прошли все, то действительно это будет быстрее, чем listdir
, хотя заметен только при работе с большими деревьями
2) Если вы перечисляете огромные каталоги, то может быть дорого сделать список, возвращаемый listdir
. (неверно, см. комментарий Алекса ниже)
однако, это, вероятно, не будет иметь значения и на самом деле может быть медленнее, из-за потенциально дополнительных накладных расходов, связанных с вызовом вашего visit
функция и выполнение всех дополнительных аргументов упаковки и распаковки.
(на самом деле единственный способ ответить на этот вопрос - проверить его самостоятельно-это займет всего несколько минут)