Хэш-предложения - это естественный способ, которым опытный Perler сделает это, но в этом случае он может быть неоптимальным.Он сканирует весь файл и создает большую плоскую структуру данных за линейное время.Более грубые методы могут закорачивать с наихудшим линейным временем, обычно на практике реже.
Сначала я создал большой файл сопоставления:
my $LEN = shift;
for (1 .. $LEN) {
my $rnd = int rand( 999 );
print "$_,$rnd\n";
}
С передачей $LEN
в командной строке как10000000, файл вышел на 113МБ.Затем я протестировал три реализации.Первый - это метод поиска по хешу.Второе выкидывает файл и сканирует его с помощью регулярного выражения.Третий читает построчно и останавливается, когда совпадает.Полная реализация:
#!/usr/bin/perl
use strict;
use warnings;
use Benchmark qw{timethese};
my $FILE = shift;
my $COUNT = 100;
my $ENTRY = 40;
slurp(); # Initial file slurp, to get it into the hard drive cache
timethese( $COUNT, {
'hash' => sub { hash_lookup( $ENTRY ) },
'scalar' => sub { scalar_lookup( $ENTRY ) },
'linebyline' => sub { line_lookup( $ENTRY ) },
});
sub slurp
{
open( my $fh, '<', $FILE ) or die "Can't open $FILE: $!\n";
undef $/;
my $s = <$fh>;
close $fh;
return $s;
}
sub hash_lookup
{
my ($entry) = @_;
my %data;
open( my $fh, '<', $FILE ) or die "Can't open $FILE: $!\n";
while( <$fh> ) {
my ($name, $val) = split /,/;
$data{$name} = $val;
}
close $fh;
return $data{$entry};
}
sub scalar_lookup
{
my ($entry) = @_;
my $data = slurp();
my ($val) = $data =~ /\A $entry , (\d+) \z/x;
return $val;
}
sub line_lookup
{
my ($entry) = @_;
my $found;
open( my $fh, '<', $FILE ) or die "Can't open $FILE: $!\n";
while( <$fh> ) {
my ($name, $val) = split /,/;
if( $name == $entry ) {
$found = $val;
last;
}
}
close $fh;
return $found;
}
Результаты в моей системе:
Benchmark: timing 100 iterations of hash, linebyline, scalar...
hash: 47 wallclock secs (18.86 usr + 27.88 sys = 46.74 CPU) @ 2.14/s (n=100)
linebyline: 47 wallclock secs (18.86 usr + 27.80 sys = 46.66 CPU) @ 2.14/s (n=100)
scalar: 42 wallclock secs (16.80 usr + 24.37 sys = 41.17 CPU) @ 2.43/s (n=100)
(Обратите внимание, что я запускаю это с SSD, поэтому ввод / вывод очень быстрый и, возможно, делает это начальнымslurp()
ненужно. YMMV.)
Интересно, что реализация hash
так же быстро, как и linebyline
, что я не ожидал.При использовании slurping scalar
может оказаться быстрее на традиционном жестком диске.
Однако самым быстрым на данный момент является простой вызов grep
:
$ time grep '^40,' int_map.txt
40,795
real 0m0.508s
user 0m0.374s
sys 0m0.046
Perl мог легко прочитать этот вывод и разделить запятую практически за любое время.
Редактировать: Не берите в голову grep.Я неправильно понял цифры.