Как я могу предварительно выделить строку в Perl?

в окне сценария кофе-скрипта Windows = = 1.9.0 не работает должным образом. просто добавьте Gemfile

 gem 'coffee-script-source', '1.8.0'

и запустите

bundle update coffee-script-source
13
задан sigjuice 2 May 2009 в 10:57
поделиться

6 ответов

Альтернативное предложение, с которым будет намного легче справиться: вставьте строки в массив и присоедините к нему, когда вы закончите.

7
ответ дан 1 December 2019 в 20:30
поделиться

Да, увеличение строки в Perl приведет к повторным перераспределениям. Perl выделяет немного дополнительного пространства для строк, но только несколько байтов. Вы можете увидеть это, используя Devel :: Peek. Это перераспределение очень быстрое и часто фактически не копирует память. Доверьтесь своему диспетчеру памяти, поэтому вы программируете на Perl, а не на C. Сначала сравните его!

Вы можете предварительно выделить массивы с помощью $ # array = $ num_entries и хешем с ключами% hash = $ num_keys , но длина $ string = $ strlen не работает. Вот умный трюк , который я выкопал на Perlmonks .

my $str = "";
vec($str, $length, 8)=0;
$str = "";

Или, если вы хотите попасть в XS, вы можете вызвать SvGROW () .

chaos ' Предложение использовать массив, а затем объединить все это будет использовать более чем вдвое больше памяти. Память для массива. Память для каждого скаляра выделяется для каждого элемента в массиве. Память для строки хранится в каждом скалярном элементе. Память на копию при присоединении. Если это приводит к более простому коду, делайте это, но не думайте, что вы экономите память.

15
ответ дан 1 December 2019 в 20:30
поделиться

Строки в Perl являются изменяемыми, поэтому добавление в строку НЕ приводит к штрафу за дублирование строки.

Вы можете попробовать все, что хотите, чтобы найти «более быстрый» способ, но это пахнет преждевременной оптимизацией.

Например, я собрал класс, который отвлекал тяжелую работу. Он работает отлично, но, несмотря на все свои глупые трюки, очень медленно.

Вот результат:

         Rate  magic normal
magic  1.72/s     --   -93%
normal 23.9/s  1289%     --

Да, верно, 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() ));
7
ответ дан 1 December 2019 в 20:30
поделиться

Да, хорошо известно, что заранее растянутые строки будут расти.

Для этого можно использовать оператор «x». Например, чтобы предварительно выделить 1000 пробелов:

$ s = "" x 1000:

-2
ответ дан 1 December 2019 в 20:30
поделиться

Я бы пошел по пути массива / соединения:

push(@array, $crunched_bit)

А затем $ str = join ('', @array) , если не более, чтобы иметь доступ к все элементы для отладки позже.

0
ответ дан 1 December 2019 в 20:30
поделиться

Я не знаю конкретно, как реализованы строки Perl, но довольно неплохо предположить, что это постоянное амортизированное время . Это означает, что даже если вы найдете способ предварительно выделить ваши строковые шансы, то, что объединенное время, которое он сэкономит для всех пользователей скрипта, будет меньше, чем время, которое вы потратили, задавая этот вопрос на переполнение стека .

3
ответ дан 1 December 2019 в 20:30
поделиться
Другие вопросы по тегам:

Похожие вопросы: