如何加快Perl处理固定宽度数据的速度?

时间:2009-10-19 13:51:20

标签: perl optimization unpack fixed-width

我们有一个成熟的代码体,可以将文件中的数据加载到数据库中。 有几种文件格式;它们都是固定宽度的字段。

部分代码使用Perl unpack()函数将输入数据中的字段读入包变量。 然后,业务逻辑能够以“人类可读”的方式引用这些字段。

在读取文件之前,文件读取代码是从格式描述生成的。

在草图形式中,生成的代码如下所示:

while ( <> ) {

    # Start of generated code.

    # Here we unpack 2 fields, real code does around 200.
    ( $FIELDS::transaction_date, $FIELDS::customer_id ) = unpack q{A8 A20};

    # Some fields have leading space removed
    # Generated code has one line like this per affected field.
    $FIELDS::customer_id =~ s/^\s+//;

    # End of generated code.

    # Then we apply business logic to the data ...
    if ( $FIELDS::transaction_date eq $today ) {
        push @fields, q{something or other};
    }

    # Write to standard format for bulk load to the database.
    print $fh join( '|', @fields ) . q{\n} or die;
}

对代码进行分析后发现,大约35%的时间花费在解包和前导空间条带上。 剩余时间用于验证和转换数据,以及写入输出文件。

业务逻辑似乎没有一部分占用运行时间的1-2%。

问题是 - 我们能否以某种方式从拆包和空间剥离中获得更多的速度?最好不必重构所有引用FIELDS包变量的代码。

修改

如果它有所作为

$ perl -v
This is perl, v5.8.0 built for PA-RISC1.1

6 个答案:

答案 0 :(得分:7)

我实际上一遍又一遍地处理这个问题。 Unpack is better than substr

就剥离空间而言,你几乎搞砸了。正则表达式黑客攻击是“官方”的方式。你可以通过改进你的unpack语句来获得一些效率(假设没有数据超过4位数,为什么要解压缩字段的完整12位?),但除此之外,解析只是一个p.i.t.a。

祝你的平面数据好运。令人沮丧的传统垃圾,我多么讨厌它。

答案 1 :(得分:3)

你确定你是这个任务的处理器吗?计算很简单,可以怀疑整个过程可能是I / O绑定的。在这种情况下,优化以便更快地解压缩不会给你带来太多时间。

如果您实际上是处理器绑定的,那么所描述的问题似乎几乎可以并行化,但当然,恶魔就在您的业务计算的细节中。

答案 2 :(得分:1)

是。使用substr进行提取可能是最快的方法。那就是:

$FIELDS::transaction_date = substr $_, 0, 8;
$FIELDS::customer_id      = substr $_, 8, 20;

可能会更快。现在,如果我手写这段代码,我就不会放弃unpack,但是如果你要生成代码,你也可以试一试。

另见Is Perl’s unpack() ever faster than substr()?

的答案

至于剥离前导空格,s/^\s+//可能是最快的方法。

更新:如果没有能够运行基准测试,很难说清楚。但是,怎么样:

my  $x  = substr $_, 0, 8;

表示不需要修剪和

的字段
my ($y) = substr($_, 8, 20) =~ /\A\s+(.+?)\s+\z/;

是否需要修剪?

答案 3 :(得分:1)

这也可能适用于XS - 因此您可以使用C函数来更改数据。我可以想象这比其他任何东西都快得多,因为你可以手动控制何时真正复制数据 由于您对C编译器具有依赖性,因此构建过程将变得更加困难,并且需要额外的集成步骤。

答案 4 :(得分:1)

简单地让它并行。它是微不足道的,甚至在任何远程现代机器上都会更快。

答案 5 :(得分:0)

我们代码的基于substr的版本的基准测试表明它可能比我们现有的unpack快约50%。 比较实际应用中的代码,substr版本使运行时间缩短了16%。 这与我们希望的基于该问题中提到的基准和分析的结果非常接近。

此优化可能对我们有用。但是,我们正在迁移到新的操作系统,所以我们将等待,然后再继续查看代码在那里的执行情况。我们添加了一项测试,以密切关注比较基准。

我们现在的成语是:

$FIELDS::transaction_date = substr( $_, 0, 8 ) || '';
$FIELDS::transaction_date =~ s/\s+\z//;
$FIELDS::customer_id = substr( $_, 8, 20 ) || '';
$FIELDS::customer_id =~ s/\s+\z//;

随后像以前一样选择性地引导空间移除。

感谢目前为止的所有答案。 我会接受思南的,因为它对我们有用,尽管看起来“只是完全错误”。