Как улучшить производительность вызовов File :: Find :: Rule? - PullRequest
9 голосов
/ 19 февраля 2011

Я использую File::Find::Rule, чтобы найти исполняемые пользователем папки на один уровень в каталоге, указанном в $dir:

my @subDirs = File::Find::Rule->permissions(isExecutable => 1, user => "$uid")->
                                extras({ follow => 1, follow_skip => 2 })->
                                directory->
                                maxdepth(1)->
                                in( $dir );

Вот примерный эквивалент с использованием UNIX findУтилита:

my $subDirStr = `find $dir -maxdepth 1 -type d -user $username -perm -100`;
chomp($subDirStr); 
my @subDirs = split("\n", $subDirStr);

Оба запускаются в сценариях, которые имеют разрешения для восстановления этих данных.

Если я запускаю оператор find в командной строке, результаты возвращаются мгновенно.

Если я выполню любое из приведенных выше утверждений с помощью сценария Perl, результаты будут работать несколько секунд.

Что я могу сделать программно, чтобы улучшить производительность любого из двух подходов Perl?

Ответы [ 3 ]

5 голосов
/ 19 февраля 2011

Я подозреваю, что задержка, которую вы видите, связана с продолжительностью времени, необходимого для получения всех результатов.Конечно, если вы перенаправите вашу команду find в less, вы сразу получите результаты, но если вы перенаправите ее в tail, вы можете увидеть задержку, похожую на ту, что вы видите в вашем скрипте Perl.

В обеих ваших альтернативных реализациях вы создаете массив со списком всех совпадающих файлов - ваш код не будет продолжаться до тех пор, пока не будет завершен процесс сопоставления файлов.

В качестве альтернативы вы можете использовать итераторный подход, подобный следующему:

my $rule = File::Find::Rule->permissions(isExecutable => 1, user => $uid)
                           ->extras({ follow => 1, follow_skip => 2 })
                           ->directory
                           ->maxdepth(1)
                           ->start($dir);
while( defined ( my $path = $rule->match ) ) {
    ...
}

Для полноты вы можете достичь аналогичного результата с помощью команды find.Вместо использования обратных кавычек вы можете явно использовать канал и читать результаты по одному:

open my $pipe, 'find $dir -maxdepth 1 -type d -user $username -perm -100|' or die "Can't run find: $!";
while(my $path = <$pipe>) {
    ...
}

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

3 голосов
/ 28 февраля 2011

Я собираюсь на данный момент проигнорировать часть File :: Find :: Rule и сосредоточиться на разнице в находке из командной строки и поиске по обратным ссылкам в perl.

Во-первых, убедитесь, что сценарий, который не выполняет ничего, кроме команды find..., все еще имеет проблему. Он запускается вами как тот же пользователь и из тех же каталогов и в тех же каталогах, что и быстро выполняющийся вызов командной строки.

Если проблема не возникает, нам нужно больше узнать о вашем сценарии. Или вам нужно удалять элементы из вашего скрипта по кусочкам, пока вам не понадобится просто выполнить команду find и посмотреть, что нужно удалить, чтобы устранить проблему.

Если это так, попробуйте использовать полный путь (например, /usr/bin/find) вместо просто find, чтобы исключить возможность различий PATH или псевдонимов оболочки, вызывающих разницу.

Также убедитесь, что выходные данные командной строки run и backticks run идентичны.

И попробуйте перенаправить вывод обоих в / dev / null (внутри обратных ссылок, для версии perl) и посмотрите, имеет ли это какое-то значение для синхронизации.

0 голосов
/ 24 февраля 2011

Вы должны понимать, что вызов команд через perl через backticks или system () заставляет perl отключить оболочку, которая затем запускает нужную команду.Это всегда будет медленнее, хотя в быстрых системах с незанятым ресурсом это может быть не очень заметно.

...