Perl中unpack和join组合的性能表现

4
我有一个用Perl编写的解析器,用于解析固定长度记录的文件。记录的一部分由几个字符串(也是固定长度)组成,仅由数字组成。字符串中的每个字符都是作为数字而不是ASCII字符编码的。例如,如果我有字符串12345,则编码为01 02 03 04 05(而不是31 32 33 34 35)。
我使用unpack解析记录,并将该特定部分解包为@array = unpack "C44", $s。然后,我使用简单的join恢复所需的字符串,例如$m = join("", @array)
我想知道这是否是解码的最佳方式。文件很大,有数百万条记录,显然我试图看看是否可能进行优化。分析器显示大部分时间都花在解析记录上(即读取、写入和其他操作不是问题),而在解析过程中,大部分时间都花在了这些join操作上。我记得从其他来源得知join是相当高效的操作。是否有任何想法可以进一步加快代码速度,或者已经是最优的了?也许可以以某种聪明的方式避免这个中间数组,例如使用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]));
    }
3个回答

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);

只需要进行小的修正,除此之外这个程序是正确的。而且比我的快了两倍。看着这个解包,我不禁想知道我是如何想出这些连接的 :( - MariusM
@MariusM 如果您告诉我需要更正的内容,我很乐意编辑我的回答。 - hobbs
1
"hex unpack 'H8'" 是一个非常绕弯的方式来执行 "unpack 'N'"。已修复。 - ikegami

0

我是一个pack/unpack新手,但是你可以通过修改你的示例代码来跳过join操作:

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

快速测试:

#!/usr/bin/perl

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

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

0

像往常一样,在Perl中,更快意味着可读性更低 :-)

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

我不相信这个改变会加速您的代码。一切都取决于您调用 join 函数读取整个文件的频率。如果您正在以块的方式处理数据,请尝试增加块的大小。如果您在 unpack 和 join 操作之间进行了某些操作,请尝试将它们与 map 操作对齐。如果您发布源代码,那么很容易确定瓶颈所在。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接