我可以告诉Perl一些数据是不可变的,以加快速度吗?

时间:2009-05-18 21:43:40

标签: perl optimization

Perl非常适合编写我通常需要做的字符串/文件解析程序。与C / C ++ / JAVA相比,我真正喜欢的是编写快速脚本和一次性代码所花费的时间。但是,我想学习如何加快速度。

例如,我想学习如何给Perl提供提示,以便它可以做出更好的决策 - 尤其是与字符串相关的事情。在我看来,Perl会在您执行任何操作时复制一个字符串,无论您是否真的稍后修改了该副本。这是设计的(我可以用一些魔法把它转走吗?)或者我在咆哮?

我真的想把一些字符串视为(const char *)。我确信我们总是不需要所有的东西都是std :: string并且涉及到所有的包袱(让我们假设std :: string类似于Perl字符串)。我可以给Perl一些暗示在某些字符串上执行此操作吗?

我记得读过一些文章(请注释,如果你可以放置它),你可以暗示Perl你不会修改某些变量,因此它会删除额外的行李,否则你需要修改它等等。

我相信Perl变量有两个内部指针指向同一个Perl变量 - 一个可以存储一个数字,另一个可以存储一个字符串(字符数组)。我是否总能告诉Perl在整个过程中选择一个?我可以让Perl将某些字符串视为(const char *),以便它们不会标记修改它们所需的功能吗?

例如,我读到某处(也许是同一篇文章?)unpack()比substr()更快,因为substr()返回一个左值,所以你也可以对它进行操作。例如,如果我想用'ef'替换字符串的前两个字符,我可以写:

substr(string, 0, 2) = 'ef'; # string now begins with 'ef'

因此,除非我使用substr()的这个特殊功能,否则最好使用substr?

我一直在咆哮吗?

4 个答案:

答案 0 :(得分:16)

您可以使用Readonly::XS在变量上设置SvREADONLY标记,但这不会提高效率。效率来自于选择正确的算法,而不是通过编译器提示。如果您希望代码更快/使用更少的内存,请对其进行分析(请参阅Devel::NYTProf)。当您发现瓶颈时,要么在其中使用不同的算法,要么切换为使用XS

另外,如果你打算尝试优化某些东西,请确保结果真的更快,这里是substr vs unpack:

            Rate unpack substr
unpack 2055647/s     --   -74%
substr 7989875/s   289%     --

以下是基准代码。

#!/usr/bin/perl

use strict;
use warnings;

use Benchmark;

my %subs = (
    unpack => sub { return unpack "a3", "foobarbaz" },
    substr => sub { return substr "foobarbaz", 0, 3 }
);

for my $sub (keys %subs) {
    print "$sub => ", $subs{$sub}(), "\n";
}

Benchmark::cmpthese -1, \%subs;

答案 1 :(得分:7)

一般来说:

使用好的算法,除非有必要,否则不进行优化。如果是,请分析您的代码并对您的更改进行基准测试。现在是根据需要考虑XS或Inline :: C的好时机。

a(const *)char equvia:

use constant Foo => 'bar';由perl编译器创建a minimal subroutine that can be inlined。您还可以创建自己的可内联常量函数

避免额外复制:

典型的perl习语会进行一些“额外”复制:

sub foo {
    my $bar = shift;

    ..do stuff with $bar...
}

许多人没有意识到Perl通过引用将参数传递给子例程。 @_包含别名到子例程的参数。

因此,您可以通过直接使用@_来避免复制您的参数:

foo( $big_scalar );

sub foo {
    ..do stuff with $_[0]...
    .. sneakily risk modifying $big_scalar ..
}

当然,这是有风险的,因为如果修改该值,您将修改调用值。仅在需要保存BIG文件副本时使用此选项。 (或者你明确想要修改一个调用参数。)

如果我需要移动一大块数据,但我不打算修改它,我通常会明确地通过引用传递它,而不是弄乱@_;

foo( \$big_scalar );
sub foo {
    my $bar = shift;
    ... do stuff with $$bar ...
    ... can modify $big_scalar, but the pass by ref is explicit ...
}

[P]重建优化是万恶之源

至少这就是唐纳德克努特所说的那句名言。这句话有很多智慧。

不正确的优化(声称是优化的代码,但不是)也非常糟糕。

首先要明确代码。 请务必对代码进行分析以找出瓶颈。 请务必对优化进行基准测试,以确保它们正常工作。 记录您的优化代码,保留一些基准代码 - 明天的编译器可能不会像今天那样响应。

答案 2 :(得分:3)

我正在使用Chas,首先对您的代码进行基准测试和分析。我真的怀疑字符串复制是你的瓶颈,你会浪费很多时间来获得微薄的收益。即使字符串复制似乎确实是瓶颈,首先在代码中查找有缺陷的算法。 Perl优于C和Java的潜在性能提升之一是因为它编写代码的速度非常快,因此可以为您提供足够的额外时间来分析和优化并改进算法。

如果字符串复制确实是您的瓶颈,请考虑简单地将大字符串作为引用传递。 C中字符串指针的道德等价物。这将阻止复制。请记住在使用它们之前取消引用它们。

sub foo {
    my $ref = shift;

    print $$ref;
}

$string = "Some string";
foo(\$string);

答案 3 :(得分:0)

  

我记得读过一些文章(如果你可以发表评论请注释),你可以提示perl你不会修改某些变量,因此它会删除额外的行李,否则你需要修改它等等? / p>

假设你在谈论'use constant ......',我是否正确?