Я недавно заметил, что быстрый сценарий, который я написал на Perl, который был разработан для использования в файлах размером менее 10 МБ, был изменен, переадресован и использован в текстовых файлах размером более 40 МБ со значительными проблемами производительности в пакетной среде.
Задания выполнялись около 12 часов за один запуск при обнаружении большого текстового файла, и мне интересно, как мне улучшить производительность кода? Должен ли я засунуть файл в память, и если я это сделаю, это нарушит зависимость заданий от номеров строк в файле. Любая конструктивная мысль будет принята с благодарностью, я знаю, что задание перебирает файл слишком много раз, но как это уменьшить?
#!/usr/bin/perl
use strict;
use warnings;
my $filename = "$ARGV[0]"; # This is needed for regular batch use
my $cancfile = "$ARGV[1]"; # This is needed for regular batch use
my @num =();
open(FILE, "<", "$filename") || error("Cannot open file ($!)");
while (<FILE>)
{
push (@num, $.) if (/^P\|/)
}
close FILE;
my $start;
my $end;
my $loop = scalar(@num);
my $counter =1;
my $test;
open (OUTCANC, ">>$cancfile") || error ("Could not open file: ($!)");
#Lets print out the letters minus the CANCEL letters
for ( 1 .. $loop )
{
$start = shift(@num) if ( ! $start );
$end = shift(@num);
my $next = $end;
$end--;
my $exclude = "FALSE";
open(FILE, "<", "$filename") || error("Cannot open file ($!)");
while (<FILE>)
{
my $line = $_;
$test = $. if ( eof );
if ( $. == $start && $line =~ /^P\|[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]\|1I\|IR\|/)
{
print OUTCANC "$line";
$exclude = "TRUECANC";
next;
}
if ( $. >= $start && $. <= $end && $exclude =~ "TRUECANC")
{
print OUTCANC "$line";
} elsif ( $. >= $start && $. <= $end && $exclude =~ "FALSE"){
print $_;
}
}
close FILE;
$end = ++$test if ( $end < $start );
$start = $next if ($next);
}
#Lets print the last letter in the file
my $exclude = "FALSE";
open(FILE, "<", "$filename") || error("Cannot open file ($!)");
while (<FILE>)
{
my $line = $_;
if ( $. == $start && $line =~ /^P\|[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]\|1I\|IR\|/)
{
$exclude = "TRUECANC";
next;
}
if ( $. >= $start && $. <= $end && $exclude =~ "TRUECANC")
{
print OUTCANC "$line";
} elsif ( $. >= $start && $. <= $end && $exclude =~ "FALSE"){
print $_;
}
}
close FILE;
close OUTCANC;
#----------------------------------------------------------------
sub message
{
my $m = shift or return;
print("$m\n");
}
sub error
{
my $e = shift || 'unknown error';
print("$0: $e\n");
exit 0;
}
exclude
, кажется, когда-либо содержит только 2 разных значения, используйте флаг 0/1, чтобы вы могли проверить его значение как логическое, а не путем текстового сопоставления в каждой строке (для удобства обслуживания вы, конечно, можете использовать константы манифеста вместо литералов 0/1) . другой вариант - прочитать файл в режиме slurp ({ local $/ = undef; $fcontent = <FILE>; }
, обратите внимание на перенос в новый блок) и сопоставить с$fcontent
, перемещаясь между совпадениями, используя привязку\G
в вашем регулярном выражении. - person collapsar   schedule 29.08.2013