Оптимизация регулярных выражений, скрипта

Привет всем!

Есть большой файл, лог, который требуется пропарсить. Выглядит он примерно так:

Date KEY=VALUE, KEY=VALUE, KEY=VALUE
Date KEY=VALUE, KEY=VALUE, KEY=VALUE
Date KEY=VALUE, KEY=VALUE, KEY=VALUE

KEY=VALUE в каждой строке много. Сам лог около 20 метров(это тестовый, реальный будет больше на много).

Интересует оптимизация вот такого кода:

open(FILE, "log.txt") or die "Can't open file: $!\n";
while(my $line = <FILE>) {
my $data;
$data->{$1} = $2 while $line =~ /([A-Z0-9-]+)=(.+?)(?:,\s|$)/g;
}

Мое мнение, что именно эта регулярка тормозит работу скрипта.

Для начала

Для начала попробовать откусить ^Date, остаток разобрать split(/,\s+/)

И попробовать регексп скомпилировать до цикла: perldoc perlop | grep qr

Да, но...

Это особо скорость не увеличивает. Может быстрее уже ничего не будет ?
Откусывать Date, кстати, не обязательно, достаточно сделать
%{$data} = map { /([A-Z0-9-]+)=(.+)/ } split( /,/, $line );

и всего делов...но работает, буквально, на пол секунды быстрее...хотелось бы заоптимайзить до 2-2,5 секунд. Больше вариантов не вижу.

Коллега,

Коллега, попробуйте блочное чтение со сплитами вместо RE. Кроме этого, использование пременных типа $` , $' etc. замедляет работу всех RE во всём скрипте. Если судить по личному опыту -- замедляет вполне существенно.

И, наконец, никто не отменял DTrace :-)

.+? - неэффективная конструкция

Советую попробовать в регулярном выражении заменить (.+?)(?:,\s|$) на ([^,\s]+). Может, будет несколько быстрее.

А вообще, мне кажется, резервов для кардинального ускорения обработки в данном случае нет (если не менять алгоритм, разумеется. Например, если лог накапливается, то можно не парсить его каждый раз с начала, а начинать с позиции, на которой прошлый раз остановились, сохраняя эту позицию (и, если нужно, предыдущие рез-ты) в файл/базу).

Да, но

%{$data} = map { /([A-Z0-9-]+)=(.+)/ } split( /,/, $line );  внутри цикла не будет накапливать хэш, будет перезаписывать. 

Можно попробовать map { /([A-Z0-9-]+)=(.+)/; $data->{$1) = $2 } split( /,/, $line ); (и заменить map на более быстрый foreach). 

Нашел галимый быстрый способ=)

Нашел самый быстрый и самый уродливый, на мой взгялд, вариант=) Первое, решил пересмотреть нужные мне KEY=VALUE - парочку отсеил.
Решил сам указывать нужные мне ключи.

Такой блок:

my $index = index( $line, "SRC-NAME" );
my $commaindex = index( $line, ",", $index );
my $len = $commaindex - $index;
$data->{'SRC-NAME'} = substr( $line, $index + 9, $len - 9 );

работает быстрее, чем
($data->{'SRC-NAME'}) = $line =~ /SRC-NAME=([^,\s]+)/;

Почему - не знаю=)

Ага. C-style :) как

Ага. C-style :) как раз собрался посоветовать.

Тривиальная задача...

... классическое решение которой является unpack и превосходно задокументировано.

Топикстартеру и всем постерам курить до озарения http://search.cpan.org/~rgarcia/perl-5.10.0/pod/perlpacktut.pod

Оптимизаторы....

-- perl -e 'sub _{{{{{{{{print for fun}}}}}}}}_'