代码之家  ›  专栏  ›  技术社区  ›  martin clayton egrunin

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

  •  5
  • martin clayton egrunin  · 技术社区  · 15 年前

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

    部分代码使用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%。

    问题是——我们能从解包和空间剥离中以某种方式提高一点速度吗?最好不要重构引用字段包变量的所有代码。

    编辑:

    以防万一

    $ perl -v
    This is perl, v5.8.0 built for PA-RISC1.1
    
    6 回复  |  直到 15 年前
        1
  •  1
  •   Community Reversed Engineer    7 年前

    对。提取使用 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/;
    

    那需要修剪吗?

        2
  •  7
  •   Community Reversed Engineer    7 年前

    我真的一次又一次地处理这个问题。 Unpack is better than substr .

    就剥离空间而言,你简直是一团糟。这个regex黑客是“官方”的方法。您可以通过优化解包语句来提高效率(假设没有数据超过4位,为什么要解包字段的完整12位?)否则,解析只是一个P.I.T.A。

    祝你的平面数据好运。废旧的垃圾,我是多么讨厌。

        3
  •  3
  •   ttarchala    15 年前

    您确定您在这个任务上绑定了处理器吗?计算非常简单,可以怀疑整个过程可能受到I/O限制。在这种情况下,优化更快的解包不会给您带来太多时间。

    如果您实际上是受处理器限制的,那么所描述的问题似乎是相当可并行的,但问题当然在您的业务计算的细节中。

        4
  •  1
  •   weismat    15 年前

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

        5
  •  1
  •   user80168    15 年前

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

        6
  •  0
  •   martin clayton    15 年前

    基于SUBSTR的代码版本的基准测试表明,它可能比现有的解包快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//;
    

    然后,像以前一样选择性地去除引导空间。

    谢谢你迄今为止的回答。 我会接受西南的,因为它对我们很有效,尽管看起来“完全错误”。