如何在Perl中预先分配字符串?

sig*_*ice 13 string perl

我有一个Perl脚本可以处理大量数据.由于重复使用点(连接)运算符,有许多字符串变量从小开始但变长很长.以这种方式增长字符串会导致重复重新分配吗?如果是,是否有预先分配字符串的方法?

Sch*_*ern 15

是的,Perl生成一个字符串将导致重复重新分配.Perl为字符串分配了一些额外的空间,但只有几个字节.你可以使用Devel :: Peek看到这个.这种重新分配非常快,通常不会实际复制内存.相信你的内存管理器,这就是你用Perl而不是C编程的原因.首先对它进行基准测试!

您可以使用$#array = $num_entries和使用散列预分配数组keys %hash = $num_keyslength $string = $strlen不起作用.这是我在Perlmonks上挖出的一个聪明的伎俩.

my $str = "";
vec($str, $length, 8)=0;
$str = "";
Run Code Online (Sandbox Code Playgroud)

或者如果你想进入XS,你可以打电话SvGROW().

混乱'建议使用一个数组,然后将它们连接在一起将使用超过两倍的内存.阵列的内存.为数组中的每个元素分配的每个标量的内存.每个标量元素中保存的字符串的内存.加入时的副本内存.如果它导致更简单的代码,那么做,但不要认为你节省了任何内存.


cha*_*aos 7

替代建议将更容易应对:字符串推入数组并在完成后加入它.

  • 尽管数组中的每个元素都会创建一个具有所有开销的SV.你会用这种方式消耗更多的内存. (7认同)

Ken*_*ric 7

Perl的字符串是变的,因此追加到一个字符串确实招致串的重复处罚.

您可以尝试所有想要找到"更快"的方式,但这对于过早优化非常糟糕.

举个例子,我掀起了一个抽象出艰苦工作的课程.它运作得很完美,但它的所有愚蠢技巧都非常慢.

这是结果:

         Rate  magic normal
magic  1.72/s     --   -93%
normal 23.9/s  1289%     --
Run Code Online (Sandbox Code Playgroud)

是的,没错,Perl比我认为的可敬实施快1200%.

描述您的代码并找出真正的问题,不要尝试优化甚至不是已知问题的东西.

#!/usr/bin/perl

use strict;
use warnings;

{

    package MagicString;
    use Moose;

    has _buffer => (
        isa => 'Str',
        is  => 'rw',
    );
    has _buffer_size => (
        isa     => 'Int',
        is      => 'rw',
        default => 0,
    );
    has step_size => (
        isa     => 'Int',
        is      => 'rw',
        default => 32768,
    );
    has _tail_pos => (
        isa     => 'Int',
        is      => 'rw',
        default => 0,
    );

    sub BUILD {
        my $self = shift;
        $self->_buffer( chr(0) x $self->step_size );
    }

    sub value {
        my $self = shift;
        return substr( $self->{buffer}, 0, $self->{_tail_pos} );
    }

    sub append {
        my $self  = shift;
        my $value = shift;
        my $L     = length($value);
        if ( ( $self->{_tail_pos} + $L ) > $self->{_buffer_size } ){
            $self->{buffer} .= (chr(0) x $self->{step_size} );
            $self->{_buffer_size} += $self->{step_size};
        }
        substr( $self->{buffer}, $self->{_tail_pos}, $L, $value );
        $self->{_tail_pos} += $L;
    }
    __PACKAGE__->meta->make_immutable;
}


use Benchmark qw( :all :hireswallclock );

cmpthese( -10 , {
        magic => sub{
            my $x = MagicString->new();
            for ( 1 .. 200001 ){
                $x->append( "hello");
            }
            my $y = $x->value();
        },
        normal =>sub{
            my $x = '';
            for ( 1 .. 200001 ){
                $x .= 'hello';
            }
            my $y = $x;
        }
    });
#use Data::Dumper;
#print Dumper( length( $x->value() ));
Run Code Online (Sandbox Code Playgroud)

  • 说Perl不重复字符串只是事实的一半.Perl只为字符串分配了几个字符,因此Perl很可能在追加时增加包含字符串的内存.这可能会导致内存被复制.但这种情况发生在系统的内存管理器中,速度非常快.记住,O(n)将在数学类中击败O(logn),但在现实世界中,算法的常数时间很重要.C很快. (3认同)