Более быстрый способ ходьбы по каталогу вместо ОС.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))

мои вопросы :

  1. если я поменяю ОС.ходить вместо ОС.listdir , это повысить производительность?
  2. как насчет использования dircache.listdir() ? кэшировать все содержимое каталога / субдира по первоначальному запросу и возвращать результаты кэша, если нет новых загруженных файлов или изменений в файле?
  3. есть ли другой способ ходьбы по каталогу, который быстрее?
  4. любой другой серверный файловый браузер, который быстро написан на 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.

с проект readme.


вы должны измерять непосредственно на машинах (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 функция и выполнение всех дополнительных аргументов упаковки и распаковки.

(на самом деле единственный способ ответить на этот вопрос - проверить его самостоятельно-это займет всего несколько минут)