justkt
justkt

Reputation: 14766

Performance with Perl Strings

I've been running across a lot of Perl code that breaks long strings up this way:

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

From my background with Java, building a string like this would be a performance no-no. Is the same true with Perl? In my searches, I have read that using join on an array of strings is the fastest way to concatenate strings, but what about when you just want to break up a string for readability? Is it better to write:

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

Or do I use join, or how should it be done?

Upvotes: 11

Views: 5339

Answers (7)

darch
darch

Reputation: 4311

In my benchmarks, join is only marginally faster than concatenation with reassignment and only on short lists of strings. Concatenation without reassignment is significantly faster than either. On longer lists, join performs conspicuously worse than concatenation with reassignment, probably because argument passing starts to dominate execution time.

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%   --

So in terms of your question, . beats .= for execution time, though not by enough that it's generally worth worrying about. Readability is almost always more important than performance, and .= is often a more readable form.

This is in the general case; as sebthebert's answer demonstrates, . is so much faster than .= in the concatenation-of-constants case that I'd be tempted to treat that as a rule.

(The benchmarks, by the way, are basically in the obvious form and I'll prefer not to repeat the code here. The only surprising thing is creating the initial strings from <DATA> so as to foil constant folding.)

D'A

Upvotes: 2

Ether
Ether

Reputation: 53986

One more thing to add to this thread that hasn't been mentioned yet -- if you can, avoid joining/concatenating these strings. Many methods will take a list of strings as arguments, not just one string, so you can just pass them individually, e.g.:

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

Upvotes: 11

sebthebert
sebthebert

Reputation: 12507

I made the benchmark ! :)

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

The results (on my iMac with 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%           --

Upvotes: 10

dirk
dirk

Reputation: 101

You don't need to do any of that stuff, you can easily just assign the whole string to a variable at once.

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

Upvotes: -1

Eric Strom
Eric Strom

Reputation: 40152

The main performance difference between your two examples is that in the first, the concatenation happens each time the code is called, whereas in the second, the constant strings will be folded together by the compiler.

So if either of these examples will be in a loop or function called many times, the second example will be faster.

This assumes the strings are known at compile time. If you are building up the strings at runtime, as fatcat1111 mentions, the join operator will be faster than repeated concatenation.

Upvotes: 3

Justin R.
Justin R.

Reputation: 24061

Camel book, p 598:

Prefer join("", . ..) to a series of concatenated strings. Multiple concatenations may cause strings to be copied back and forth multiple times. The join operator avoids this.

Upvotes: 16

JSBձոգչ
JSBձոգչ

Reputation: 41378

Use whichever one you like better; the performance of those is exactly the same in perl. Perl strings are not like Java strings, and can be modified in-place.

Upvotes: 1

Related Questions