Производительность со строками Perl

Я натыкался на большое количество кода Perl, который повреждает длинные строки этот путь:

my $string = "Hi, I am a very long and chatty string that just won't";
$string .= " quit.  I'm going to keep going, and going, and going,";
$string .= " kind of like the Energizer bunny.  What are you going to";
$string .= " do about it?";

Моего образования с Java, создавая строку как это была бы производительность нет - нет. Действительно ли то же верно с Perl? В моих поисках я считал то использование join на массиве строк самый быстрый путь для конкатенации строк, но что относительно того, когда Вы просто хотите разбить строку для удобочитаемости? Лучше записать:

my $string = "Hi, I am a very long and chatty string that just won't" .
    " quit.  I'm going to keep going, and going, and going," .
    " kind of like the Energizer bunny.  What are you going to" .
    " do about it?";

Или сделайте я использую join, или как это должно быть сделано?

10
задан justkt 23 June 2010 в 18:38
поделиться

7 ответов

Camel book, p 598:

Предпочитайте join("", ...) для серии конкатенированных строк. Многочисленные конкатенации может привести к тому, что строки будут копирование туда и обратно несколько раз. Оператор join позволяет избежать этого.

15
ответ дан 3 December 2019 в 13:47
поделиться

Я прошел тест! :)

#!/usr/bin/perl

use warnings;
use strict;

use Benchmark qw(cmpthese timethese);

my $bench = timethese($ARGV[1], {

  multi_concat => sub {
    my $string = "Hi, I am a very long and chatty string that just won't";
    $string .= " quit.  I'm going to keep going, and going, and going,";
    $string .= " kind of like the Energizer bunny.  What are you going to";
    $string .= " do about it?";
  },

  one_concat => sub {
    my $string = "Hi, I am a very long and chatty string that just won't" .
    " quit.  I'm going to keep going, and going, and going," .
    " kind of like the Energizer bunny.  What are you going to" .
    " do about it?";
  },

  join => sub {
    my $string = join("", "Hi, I am a very long and chatty string that just won't",
    " quit.  I'm going to keep going, and going, and going,",
    " kind of like the Energizer bunny.  What are you going to",
    " do about it?"
    );
  },

} );

cmpthese $bench;

1;

Результаты (на моем iMac с Perl 5.8.9):

imac:Benchmarks seb$ ./strings.pl 1000
Benchmark: running join, multi_concat, one_concat for at least 3 CPU seconds...
      join:  2 wallclock secs ( 3.13 usr +  0.01 sys =  3.14 CPU) @ 3235869.43/s (n=10160630)
multi_concat:  3 wallclock secs ( 3.20 usr + -0.01 sys =  3.19 CPU) @ 3094491.85/s (n=9871429)
one_concat:  2 wallclock secs ( 3.43 usr +  0.01 sys =  3.44 CPU) @ 12602343.60/s (n=43352062)
                   Rate multi_concat         join   one_concat
multi_concat  3094492/s           --          -4%         -75%
join          3235869/s           5%           --         -74%
one_concat   12602344/s         307%         289%           --
10
ответ дан 3 December 2019 в 13:47
поделиться

Вам не нужно делать ничего из этого, вы можете просто присвоить всю строку переменной сразу.

my $string = "Hi, I am a very long and  chatty string that just won't
 quit.   I'm going to keep going, and going,  and going,
 kind of like the Energizer  bunny.  What are you going to
 do  about it?"; 
-1
ответ дан 3 December 2019 в 13:47
поделиться

Используйте тот, который вам больше нравится; производительность в Perl такая же. Строки Perl не похожи на строки Java и могут быть изменены на месте.

1
ответ дан 3 December 2019 в 13:47
поделиться

В моих тестах join лишь незначительно быстрее конкатенации с переназначением и только на коротких списках строк. Конкатенация без переназначения значительно быстрее, чем любой из этих методов. На более длинных списках join работает заметно хуже, чем конкатенация с переназначением, вероятно, потому что передача аргументов начинает преобладать над временем выполнения.

4 strings:
          Rate   .= join    .
.=   2538071/s   --  -4% -18%
join 2645503/s   4%   -- -15%
.    3105590/s  22%  17%   --
1_000 strings:
         Rate join   .=
join 152439/s   -- -40%
.=   253807/s  66%   --

Итак, с точки зрения вашего вопроса, . выигрывает у .= по времени выполнения, хотя и не настолько, чтобы об этом стоило беспокоиться. Читабельность почти всегда важнее производительности, и .= часто является более читабельной формой.

Это в общем случае; как показывает ответ sebthebert'а, . настолько быстрее, чем .= в случае конкатенации констант, что у меня возникло бы желание считать это правилом.

(Бенчмарки, кстати, в основном в очевидной форме, и я предпочту не повторять здесь код. Единственное, что удивляет, это создание начальных строк из , чтобы избежать складывания констант.)

D'A

2
ответ дан 3 December 2019 в 13:47
поделиться

Еще одна вещь, которую нужно добавить в этот поток, о которой еще не упоминалось - по возможности избегайте объединения / конкатенации этих строк. Многие методы принимают в качестве аргументов список строк, а не только одну строку, поэтому вы можете просто передавать их по отдельности, например:

print "this is",
    " perfectly legal",
    " because print will happily",
    " take a list and send all the",
    " strings to the output stream\n";

die "this is also",
    " perfectly acceptable";

use Log::Log4perl :easy; use Data::Dumper;
INFO("and this is just fine",
    " as well");

INFO(sub {
    local $Data::Dumper::Maxdepth = 1;
    "also note that many libraries will",
    " accept subrefs, in which you",
    " can perform operations which",
    " return a list of strings...",
    Dumper($obj);
 });
11
ответ дан 3 December 2019 в 13:47
поделиться

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

Поэтому, если любой из этих примеров будет находиться в цикле или функции, вызываемой много раз, второй пример будет быстрее.

Это предполагает, что строки известны во время компиляции. Если вы собираете строки во время выполнения, как упоминает fatcat1111, оператор join будет быстрее, чем повторная конкатенация.

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

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