2012-05-03 2 views
4

У меня есть парсер, написанный на Perl, который анализирует файл записей фиксированной длины. Часть записи состоит из нескольких строк (также фиксированной длины), состоящих только из чисел. Каждый символ в строке кодируется как число, а не как символ ASCII. I.e., если у меня есть строка 12345, она кодируется как 01 02 03 04 05 (вместо 31 32 33 34 35).производительность распаковки в сочетании с объединением в Perl

Я разбираю запись с распаковкой, и эта конкретная часть распакована как @array = unpack "C44", $s. Затем я восстанавливаю необходимую строку с простым соединением, например $m = join("", @array).

Мне было интересно, если это оптимальный способ декодирования. Файлы довольно большие, миллионы записей, и, очевидно, я пытался посмотреть, можно ли оптимизировать. Профилировщик показывает, что большую часть времени тратится на разбор записей (т. Е. Чтение, письмо и другие вещи не проблема), и в синтаксическом анализе большую часть времени были предприняты этими объединениями. Я помню из других источников, что объединение - довольно эффективная операция. Любые идеи, если можно быстрее скопировать код или это уже оптимально? Возможно, можно было бы избежать этого промежуточного массива каким-то умным способом, например, использовать комбинацию pack/unpack?

Отредактировано: пример кода

код, который я пытаюсь оптимизировать выглядит следующим образом:

while (read(READ, $buf, $rec_l) == $rec_l) { 
     my @s = unpack "A24 C44 H8", $buf; 
     my $msisdn = substr $s[0], 0, 11; 
     my $address = join("", @s[4..14]); 
     my $imsi = join("", @s[25..39]); 
     my $ts = localtime(hex($s[45])); 
    } 

ответ

0

Как всегда в Perl, быстрее менее читаемым :-)

join("", unpack("C44", $s)) 

Я не верю, что это изменение ускорит ваш код. Все зависит от того, как часто вы вызываете функцию соединения для чтения одного целого файла. Если вы работаете в кусках, попробуйте увеличить их размер. Если вы выполняете некоторую операцию между распаковкой и соединением с этим массивом, попробуйте выровнять их с помощью операции с картой. Если вы опубликуете исходный код, было бы легче определить узкое место.

+0

Добавил больше кода на вопрос. – MariusM

0

Я упаковка/распаковка нуб, но как насчет пропуска объединения, изменяя свой образец кода, например, так:

my $m = unpack "H*", $s ; 

быстрый тест:

#!/usr/bin/perl 

use strict ; 
use Test::More tests => 1 ; 

is(unpack("H*", "\x12\x34\x56"),"123456"); 
6

непроверенная (я приду назад и отредактируйте, когда я занят меньше), но это должно сработать, если я правильно выполнил всю математику и буду быстрее:

my ($msisdn, $address, $imsi, $ts) = 
    unpack "A11 x13 x3 a10 x10 a15 x5 N", $buf; 
$address |= "0" x 10; 
$imsi |= "0" x 15 
$ts = localtime($ts); 
+0

Необходима только небольшая коррекция, кроме того, что это работает правильно. И в два раза быстрее, чем у меня. Заглядывая в эту распаковку, я задаюсь вопросом, как мне удалось придумать эти соединения :( – MariusM

+0

@MariusM, если вы скажете мне, что такое коррекция, я с удовольствием отредактирую свой ответ. – hobbs

+1

'hex unpack 'H8'' является очень окольный способ делать 'unpack 'N''. Исправлено. – ikegami