Reputation: 14766
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
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
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
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
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
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
Reputation: 24061
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
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