9

я бегу через много кода Perl, который разбивает длинные строки, этот путь:Performance с 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, или как это должно быть сделано?

+1

Некоторые считают первую форму наиболее читаемой. И я не вижу никаких реальных оснований для беспокойства, которое происходит быстрее. – ysth

+0

@ysth - Вы когда-нибудь были программистом на Java? Тогда вы бы :). – justkt

+0

Это не имеет смысла. Потому что Java настолько «медленный»? Потому что Java-программисты являются упрямыми преждевременными оптимизаторами? – ysth

ответ

15

Camel book, p 598:

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

+1

Возможно, это был обряд @ написанного времени. Это не в perl 5.18. 'perl -Mstrict -MBenchmark -we 'timethis -10, sub {my $ output =" "; foreach (1 .. 10000) {$ output. = chr (rand (127)) x1234; }} ''на моей машине возвращается' 11 secclock secs (10.71 usr + 0.00 sys = 10.71 CPU) @ 491.13/s (n = 5260) 'while' perl -Mstrict -MBenchmark -we' timethis -10, sub {my @ глыбы; foreach (1 ..10000) {push @chunks, chr (rand (127)) x1234; } my $ output = join ("", @ chunks); } ''возвращает 11 секунд разгона (10.56 usr + 0.00 sys = 10.56 CPU) @ 134.09/s (n = 1416). Это фактор 3, который: = биты push + join. –

1

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

+0

Производительность двух примеров одинакова, или производительность 'join' такая же, как в примере? У меня есть немного времени, полагая, что 'join' одинаково (поскольку' join' обычно является полностью собственным вызовом функции), но если бы какой-либо язык оптимизировал оператор конкатенации строк, я уверен, что это 'd be perl ... –

+0

Concat не так эффективен, как join. См. Мой ответ по этой причине. –

+2

Производительность обоих примеров одинакова. Производительность 'join' - это что-то еще, что может быть больше и может быть меньше. В любом случае perl не является высокопроизводительным языком, и стоимость конкатенации строк или вызова 'join' вряд ли будет иметь значение. –

3

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

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

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

-1

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

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?"; 
+6

Это будет содержать строки в строке, что, вероятно, не то, что пользователь хочет. – Ether

+0

@Ether - правильный. Опоры для того, чтобы не называть меня «он», кстати. Это происходит постоянно, по какой-то причине, когда я не мужчина. – justkt

+0

@justkt: Я тоже. * high5 * :) – Ether

11

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

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); 
}); 
+0

Это очень полезно знать. – justkt

10

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

#!/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; 

Результаты (на мой компьютер с 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%   -- 
+7

'one_concat' оптимизируется компилятором в постоянное задание с 0 конкатенациями во время выполнения. –

+0

@ Эрик. Спасибо, что в значительной степени отвечает на мой оригинальный вопрос. – justkt

2

В моих тестах, 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's answer, . намного быстрее, чем .=, в случае с конкатенацией констант, к которому я, как правило, испытываю соблазн.

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

D'A

Смежные вопросы