10

長い文字列を次のように分割する多くの 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する必要がありますか、またはどのように行う必要がありますか?

4

7 に答える 7

16

ラクダの本、p 598 :

一連の連結文字列よりも join("", ..) を優先します。複数の連結により、文字列が何度も前後にコピーされる場合があります。結合演算子はこれを回避します。

于 2010-06-23T18:46:14.627 に答える
11

このスレッドにまだ言及されていないことをもう 1 つ追加します。可能であれば、これらの文字列の結合/連結を避けてください。多くのメソッドは、1 つの文字列だけでなく、文字列のリストを引数として受け取るため、個別に渡すことができます。たとえば、次のようになります。

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);
 });
于 2010-06-23T21:06:27.867 に答える
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;

結果 (私の 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%           --
于 2010-06-23T23:56:37.967 に答える
3

2 つの例の主なパフォーマンスの違いは、最初の例ではコードが呼び出されるたびに連結が行われるのに対し、2 番目の例ではコンパイラによって定数文字列が折りたたまれることです。

したがって、これらの例のいずれかが何度も呼び出されるループまたは関数内にある場合、2 番目の例の方が高速です。

これは、文字列がコンパイル時に認識されていることを前提としています。fatcat1111言及したように、実行時に文字列を構築している場合、join演算子は連結を繰り返すよりも高速です。

于 2010-06-23T20:12:44.420 に答える
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>一定の折りたたみを無効にするために最初の文字列を作成することです。)

于 2010-06-24T04:01:49.507 に答える
1

好きな方を使用してください。これらのパフォーマンスは、perl でもまったく同じです。Perl 文字列は Java 文字列とは異なり、その場で変更できます。

于 2010-06-23T18:41:31.643 に答える
-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?"; 
于 2010-06-23T20:59:58.737 に答える