Итак, под «хэшированием» я полагаю, вы имеете в виду выполнение контрольной суммы на уровне файла или строки, чтобы вам не приходилось проверять ее снова?
Основная проблема, контрольная сумма или нет, вы все еще должны прочитать каждую строку каждого файла либо для сканирования, либо для хеширования. Таким образом, это принципиально не меняет ваш алгоритм, а просто изменяет константы.
Если у вас много повторяющихся файлов, проверка контрольных сумм на уровне файлов может сэкономить вам много времени. Если вы этого не сделаете, это потратит много времени.
cost = (checksum_cost * num_files) + (regex_cost * lines_per(unique_files))
Проверка контрольных сумм на уровне строк - это сложность между стоимостью регулярного выражения и стоимостью контрольной суммы. Если дубликатов не так много, вы проигрываете. Если ваша контрольная сумма слишком дорогая, вы проигрываете. Вы можете написать это так:
cost = (checksum_cost * total_lines) + (regex_cost * (total_lines - duplicate_lines))
Я бы начал с выяснения, какой процент файлов и строк являются дубликатами. Это так просто, как:
$line_frequency{ checksum($line) }++
, а затем посмотреть на процент, где частота >= 2
. Этот процент представляет собой увеличение производительности максимум , которое вы увидите при проверке контрольной суммы. Если это 50%, вы увидите увеличение только на 50%. Это предполагает, что стоимость контрольной суммы равна 0, а это не так, так что вы увидите меньше. Если контрольная сумма стоит вдвое меньше, чем регулярное выражение, вы увидите только 25%.
Вот почему я рекомендую grep. Он будет перебирать файлы и строки быстрее, чем Perl может атаковать фундаментальную проблему: вы должны прочитать каждый файл и каждую строку.
То, что вы можете сделать, это не просматривать каждый файл каждый раз. Простая вещь, которую нужно сделать, это запомнить последний раз, когда вы сканировали, и посмотреть на время изменения каждого файла. Это не изменилось, и ваше регулярное выражение не изменилось, не проверяйте это снова. Более надежная версия будет хранить контрольные суммы каждого файла, в случае, если файл был изменен во время изменения. Если все ваши файлы меняются не очень часто, это приведет к большой победе.
# Write a timestamp file at the top of the directory you're scanning
sub set_last_scan_time {
my $dir = shift;
my $file = "$dir/.last_scan";
open my $fh, ">", $file or die "Can't open $file for writing: $!";
print $fh time;
return
}
# Read the timestamp file
sub get_last_scan_time {
my $dir = shift;
my $file = "$dir/.last_scan";
return 0 unless -e $file;
open my $fh, "<", $file or die "Can't open $file: $!";
my $time = <$fh>;
chomp $time;
return $time;
}
use File::Slurp 'read_file';
use File::stat;
my $last_scan_time = get_last_scan_time($dir);
# Place the regex outside the routine just to make things tidier.
my $regex = qr{this|that|blah|...};
my @huhFiles;
sub scan_file {
# Only scan text files
return unless -T $_;
# Don't bother scanning if it hasn't changed
return if stat($_)->mtime < $last_scan_time;
push(@huhFiles, $_) if read_file($_) =~ $regex;
}
# Set the scan time to before you start so if anything is edited
# while you're scanning you'll catch it next time.
set_last_scan_time($dir);
find(\&scan_file, $dir);