Производительность с помощью Perl Strings - PullRequest
10 голосов
/ 23 июня 2010

Я работал с большим количеством кода 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, или как это должно быть сделано?

Ответы [ 7 ]

15 голосов
/ 23 июня 2010

Книга верблюдов, стр. 598 :

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

11 голосов
/ 24 июня 2010

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

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);
 });
10 голосов
/ 24 июня 2010

Я сделал тест!:)

#!/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%           --
3 голосов
/ 24 июня 2010

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

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

2 голосов
/ 24 июня 2010

В моих тестах 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%   --

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

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

(Кстати, тесты в основном в очевидной форме, и я предпочту не повторять здесь код. Единственное удивительное - это создание начальных строк из <DATA>, чтобы помешать постоянному свертыванию.)

D'A

1 голос
/ 23 июня 2010

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

0 голосов
/ 24 июня 2010

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

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?"; 
...