Вот эталонный тест, использующий моё решение простого чтения файловых файлов по сравнению с регулярным выражением Шверна и связью Часов.
Это Perl 5.12.2, работающий на моем Mac Pro:
Rate Chas. Chas. modified drewk Schwern Chas. sane drewk2 brian
Chas. 70.0/s -- -33% -94% -94% -95% -95% -96%
Chas. modified 104/s 48% -- -91% -91% -92% -93% -94%
drewk 1163/s 1560% 1019% -- -5% -15% -23% -35%
Schwern 1220/s 1641% 1073% 5% -- -11% -20% -32%
Chas. sane 1370/s 1856% 1218% 18% 12% -- -10% -23%
drewk2 1515/s 2064% 1358% 30% 24% 11% -- -15%
brian 1786/s 2450% 1618% 54% 46% 30% 18% --
Это Perl 5.10.1 на той же машине:
Rate Chas. Chas. modified drewk Schwern Chas. sane drewk2 brian
Chas. 66.9/s -- -35% -94% -95% -95% -96% -96%
Chas. modified 103/s 54% -- -91% -92% -93% -93% -94%
drewk 1111/s 1560% 981% -- -17% -22% -27% -40%
Schwern 1333/s 1892% 1197% 20% -- -7% -12% -28%
Chas. sane 1429/s 2034% 1290% 29% 7% -- -6% -23%
drewk2 1515/s 2164% 1374% 36% 14% 6% -- -18%
brian 1852/s 2667% 1702% 67% 39% 30% 22% --
Эти результаты меня не сильно удивляют. Tie :: File кажется медленнее, чем должно быть, но я ожидал, что он будет медленным. Это изящно, но я нахожу, что Tie :: File часто плохо компенсирует производительность для хорошего интерфейса с чем-то, что было не так уж сложно начать. Хорошо, если вам нужен случайный и повторный доступ, но для последовательного доступа за один проход это неправильный инструмент. Чес. делает немного больше работы, чем я думаю, что он действительно нуждается в этом примере. Мы знаем индексы строк, которые нам нужны, поэтому мы можем просто взять кусок связанного массива. Срез примерно на 150% быстрее, чем цикл while
, который просматривает каждую строку.
Чтобы увидеть экстремальный результат, я реплицировал строки в 1000 раз (то есть около 1 300 000 строк в файле):
$scalar = slurp( $file ) x 1000;
Это результаты для большого файла на Perl 5.12.2:
Rate Chas. Chas. modified drewk drewk2 Schwern Chas. sane brian
Chas. 0.695/s -- -32% -91% -94% -94% -95% -96%
Chas. modified 1.02/s 46% -- -86% -91% -92% -93% -94%
drewk 7.38/s 962% 626% -- -34% -39% -47% -59%
drewk2 11.2/s 1512% 1002% 52% -- -7% -19% -38%
Schwern 12.1/s 1635% 1086% 63% 8% -- -13% -33%
Chas. sane 13.9/s 1896% 1264% 88% 24% 15% -- -23%
brian 18.0/s 2495% 1674% 144% 61% 50% 30% --
Решения Дрюка, создающие новые массивы, теперь показывают проблему масштабирования. Поскольку они не проще, чем другие решения, и у них есть этот большой недостаток, нет причин делать это таким образом.
Вот моя тестовая программа. Там очень небольшая разница в программах. Мое решение (и первое решение Chas.) Получает 1, 10, 20 и т. Д. Строки, как отмечено в тексте вопроса. Другие решения получают 1-е, 11-е, 21-е и т. Д. Строки, как отмечено в неработающем коде Это не имеет большого значения для теста.
#!perl
use strict;
use warnings;
use File::Slurp qw(slurp);
use Tie::File;
use Benchmark qw(cmpthese);
use vars qw($scalar);
chomp( my $file = `perldoc -l perlfaq5` );
#$file = '/Users/brian/Desktop/lines';
print "file is $file\n";
$scalar = slurp( $file );
cmpthese( 1000, {
'Chas.' => \&chas,
'Schwern' => \&schwern,
'brian' => \&brian,
'Chas. modified' => \&chas_modified,
'Chas. sane' => \&chas_sane,
'drewk' => \&drewk,
'drewk2' => \&drewk2,
});
sub drewk {
my @arr = split(/\n/, $scalar);
my @found;
for(my $i=0; $i<=$#arr; $i+=10){
# print "drewk[$i] $arr[$i]\n";
push @found, $arr[$i];
}
}
sub drewk2 {
my $i=0;
my @found;
foreach(split(/\n/, $scalar)) {
next if $i++ % 10;
# print "drewk2[$i] $_\n";
push @found, $_;
}
}
sub schwern {
my $count = 0;
my @found;
while($scalar =~ /\G(.*)\n/g) {
next if $count++ % 10 != 0;
# print "schwern[$count] $1\n";
push @found, $1;
}
}
sub chas {
open my $fh, "<", \$scalar;
tie my @lines, "Tie::File", $fh
or die "could not tie in-memory file: $!";
my $i = 0;
my @found = ();
while (defined $lines[$i]) {
# print "chas[$i]: $lines[$i]\n";
push @found, $lines[$i];
} continue {
$i += 10;
}
}
sub chas_modified {
open my $fh, "<", \$scalar;
tie my @lines, "Tie::File", $fh
or die "could not tie in-memory file: $!";
my $highest_multiple = int( $#lines / 10 ) ;
my @found = @lines[ map { $_ * 10 - ($_?1:0) } 0 .. $highest_multiple ];
#print join "\n", @found;
}
sub chas_sane {
open my $fh, "<", \$scalar;
my @found;
while (my $line = <$fh>) {
if ($. == 1 or not $. % 10) {
#print "chas_sane[$.] $line";
push @found, $_;
}
}
}
sub brian {
open my $fh, '<', \$scalar;
my @found = scalar <$fh>;
while( <$fh> ) {
next if $. % 10;
#print "brian[$.] $_";
push @found, $_;
}
}