Perl 中 unpack 结合 join 的性能

Posted

技术标签:

【中文标题】Perl 中 unpack 结合 join 的性能【英文标题】:performance of unpack combined with join in Perl 【发布时间】:2012-05-03 10:45:10 【问题描述】:

我有一个用 Perl 编写的解析器,它解析固定长度记录的文件。部分记录由几个字符串(也是固定长度)组成,仅由数字组成。字符串中的每个字符都被编码为数字,而不是 ASCII 字符。即,如果我有字符串 12345,它被编码为 01 02 03 04 05(而不是 31 32 33 34 35)。

我用 unpack 解析记录,这个特定部分被解包为@array = unpack "C44", $s。然后我用简单的连接恢复所需的字符串,比如$m = join("", @array)

我想知道这是否是一种最佳的解码方式。文件很大,有数百万条记录,显然我试图看看是否可以优化。 Profiler 显示大部分时间都花在了解析记录上(即,读、写和其他东西都不是问题),而解析大部分时间都花在了这些连接上。我记得从其他来源那里加入是非常有效的操作。有什么想法可以加快代码速度还是已经达到最佳状态?也许可以通过一些巧妙的方式来避免这个中间数组,例如,使用打包/解包组合来代替?

已编辑:代码示例

我尝试优化的代码如下所示:

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

【问题讨论】:

【参考方案1】:

未经测试(我会在不忙的时候回来编辑)但是如果我正确地完成了所有数学运算,这应该可以工作,并且更快:

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 如果你告诉我更正是什么,我很乐意编辑我的答案。 hex unpack 'H8' 是一种非常迂回的做法unpack 'N'。固定。【参考方案2】:

与 Perl 一样,速度越快可读性越差 :-)

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

我认为这种更改不会加快您的代码速度。一切都取决于您调用 join 函数读取整个文件的频率。如果您正在分块工作,请尝试增加它们的大小。如果您在解包和加入此数组之间进行一些操作,请尝试将它们与 map 操作对齐。如果您发布源代码,则更容易识别瓶颈。

【讨论】:

【参考方案3】:

我是一个打包/解包的菜鸟,但是通过像这样更改您的示例代码来跳过加入怎么样:

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

快速测试:

#!/usr/bin/perl

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

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

【讨论】:

以上是关于Perl 中 unpack 结合 join 的性能的主要内容,如果未能解决你的问题,请参考以下文章

perl中的pack与unpack

如何在 Perl 中使用“打包/解包”?

关于 unpack() 和 printf() 中的 v 标志的 Perl 问题

我可以使用 Perl 的 unpack 将字符串分解为 vars 吗?

MySQL结合where子句的join性能

获取 Perl 打包/解包模板的元素数量