Ускорение доступа к файловой системе? - PullRequest
10 голосов
/ 18 декабря 2009

Мое приложение сканирует часть файловой системы, и мои пользователи сообщили, что это было очень медленно, когда они сканировали сетевой диск. Тестируя мой код, я обнаружил узкое место: методы File.isFile(), File.isDirectory() и File.isHidden(), которые все вызывают fs.getBooleanAttributes(File f). Этот метод очень медленный на сетевых дисках Windows. Как я могу улучшить производительность? Могу ли я избежать вызова этого метода каким-либо образом?

Ответы [ 5 ]

10 голосов
/ 18 декабря 2009

Защитный код часто вызывает эти isXYZ() методы, и, как правило, это хорошая практика. Однако, как вы обнаружили, иногда производительность низкая.

Альтернативный подход состоит в том, чтобы предположить, что файл является файлом, он существует, он видим, доступен для чтения и т. Д., И просто попытаться прочитать его. Если это не те вещи, вы получите исключение, которое вы можете поймать, а затем выполните проверки, чтобы точно выяснить, что пошло не так. Таким образом, вы оптимизируете для общего случая (то есть все в порядке) и выполняете медленные операции только тогда, когда что-то идет не так.

6 голосов
/ 18 декабря 2009

Как вы строите этот список файлов? Если вы не отображаете каждый файл в системе одновременно, у вас должны быть некоторые параметры ...

  1. Обрабатывать эту информацию только по запросу пользователя. например Они нажимают на папку «Windows», после чего вы можете обрабатывать файлы в Windows.
  2. Обрабатывайте эту информацию в фоновом потоке, создавая иллюзию лучшего времени отклика.

Возможно, если вы покажете код, который вы используете для построения списка, мы могли бы найти некоторые другие области улучшения. (Почему вы не можете просто определить тип, основываясь на методе, используемом для сбора информации? Если вы вызываете метод, такой как GetFiles (), разве вы не знаете, что все возвращенное является файлом?)

3 голосов
/ 18 декабря 2009

Я столкнулся с точно такой же проблемой

Решение для нашего случая было довольно простым: поскольку наша структура каталогов следовала стандарту (там, где в каталоге не было символа «.»), Я просто следовал стандарту и применил очень простую эвристику: «в нашем случае каталоги не имеют«. » персонаж в его имени ". Эта простая эвристика значительно сократила количество вызовов нашего приложения функцией isDirectory () класса java.io.File.

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

2 голосов
/ 19 декабря 2009

Вот пример кода до и после использования listFiles и использования isDirectory для обхода дерева каталогов (мой код использует общий обратный вызов, чтобы фактически что-то делать с каждым каталогом и файлом; если бы я кодировал C #, это делегат).

Как вы можете видеть, подход listFiles на самом деле более компактен и легко понятен, а также немного быстрее на локальном диске (950 мс против 1000 мс) и на диске LAN (26 секунд, против 28 секунд), оба за 23 тысячи файлов.

Вполне возможно, что для удаленного подключенного диска ускорение может быть значительным, но я не могу проверить это с работы. Удивительно, но это ускорение составляет всего около 10% в Windows RAS VPN. к сетевому диску.

Новый код

static public int processDirectory(File dir, Callback cbk, FileSelector sel) {
    dir=dir.getAbsoluteFile();
    return _processDirectory(dir.getParentFile(),dir,new Callback.WithParams(cbk,2),sel);
    }

static private int _processDirectory(File par, File fil, Callback.WithParams cbk, FileSelector sel) {
    File[]                              ents=(sel==null ? fil.listFiles() : fil.listFiles(sel));    // listFiles returns null if fil is not a directory
    int                                 cnt=1;

    if(ents!=null) {
        cbk.invoke(fil,null);
        for(int xa=0; xa<ents.length; xa++) { cnt+=_processDirectory(fil,ents[xa],cbk,sel); }
        }
    else {
        cbk.invoke(par,fil);                                                    // par can never be null
        }
    return cnt;
    }

Старый код

static public int oldProcessDirectory(File dir, Callback cbk, FileSelector sel) {
    dir=dir.getAbsoluteFile();
    return _processDirectory(dir,new Callback.WithParams(cbk,2),sel);
    }

static private int _processDirectory(File dir, Callback.WithParams cbk, FileSelector sel) {
    File[]                              ents=(sel==null ? dir.listFiles() : dir.listFiles(sel));
    int                                 cnt=1;

    cbk.invoke(dir,null);

    if(ents!=null) {
        for(int xa=0; xa<ents.length; xa++) {
            File                        ent=ents[xa];

            if(!ent.isDirectory()) {
                cbk.invoke(dir,ent);
                ents[xa]=null;
                cnt++;
                }
            }
        for(int xa=0; xa<ents.length; xa++) {
            File                        ent=ents[xa];

            if(ent!=null) {
                cnt+=_processDirectory(ent,cbk,sel);
                }
            }
        }
    return cnt;
    }
0 голосов
/ 19 декабря 2009

На случай, если вы еще не пробовали, вызов getBooleanAttributes самостоятельно и выполнение необходимой маскировки будет значительно быстрее, если вы выполняете несколько проверок для одного и того же файла. Хотя это и не идеальное решение (и которое начинает подталкивать ваш код к конкретным платформам), оно может повысить производительность в 3 или 4 раза. Это довольно значительное повышение производительности, хотя и не такое быстрое, как должно быть.

Функциональные возможности jDK7 java.nio.file.Path должны немного помочь в этом.

Наконец, если у вас есть какой-либо контроль над средой конечного пользователя, предложите вашим пользователям настроить антивирусное программное обеспечение так, чтобы оно не сканировало сетевые диски. Во многих крупных AV-решениях (не уверен, что именно они решают) эта функция включена по умолчанию. Я не знаю, какое влияние это может оказать на различные методы File, но мы обнаружили, что неправильно настроенный антивирус может вызывать проблемы с задержкой практически при любом доступе к файлам на сетевых ресурсах.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...