Я натыкался на большое количество кода 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
, или как это должно быть сделано?
Предпочитайте join("", ...) для серии конкатенированных строк. Многочисленные конкатенации может привести к тому, что строки будут копирование туда и обратно несколько раз. Оператор join позволяет избежать этого.
Я прошел тест! :)
#!/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% --
Вам не нужно делать ничего из этого, вы можете просто присвоить всю строку переменной сразу.
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?";
Используйте тот, который вам больше нравится; производительность в Perl такая же. Строки Perl не похожи на строки Java и могут быть изменены на месте.
В моих тестах 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
Еще одна вещь, которую нужно добавить в этот поток, о которой еще не упоминалось - по возможности избегайте объединения / конкатенации этих строк. Многие методы принимают в качестве аргументов список строк, а не только одну строку, поэтому вы можете просто передавать их по отдельности, например:
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);
});
Основная разница в производительности между двумя примерами заключается в том, что в первом случае конкатенация происходит каждый раз при вызове кода, в то время как во втором случае константные строки будут складываться компилятором.
Поэтому, если любой из этих примеров будет находиться в цикле или функции, вызываемой много раз, второй пример будет быстрее.
Это предполагает, что строки известны во время компиляции. Если вы собираете строки во время выполнения, как упоминает fatcat1111
, оператор join
будет быстрее, чем повторная конкатенация.