In the previous article I alluded to the fact I had more to say on the approach I had to creating my test strings for those experiments. This'll just be short, as it's a variation on the same theme, and I just thought I'd share this with you.
For the previous tests I saved a million-char randomly generated string to test on. Whilst writing the code for this, I noticed some significant performance differences in various different techniques I was using to build the string. And these are perhaps worth remembering, as far as potential optimisations go.
Here's a simplification of the code I used to generate these strings. I've take the randomness out as it's irrelevant to what I'm showing here, plus I just create the string, I don't save it to disk:
This is similar to the other code, in that it allows some options:
- magnitude of string size (a power of ten)
- a method to create the string. One of:
- String
- StringBuffer
- cfsavecontent
// string.cfm
startTime = getTickCount();
s = "";
for (i=1; i <= stringLength; i++){
s &= "X";
}
endTime = getTickCount();
// stringBuffer.cfm
startTime = getTickCount();
sb = createObject("java", "java.lang.StringBuffer").init(stringLength);
for (i=1; i <= stringLength; i++){
sb.append("X");
}
s = sb.ToString();
endTime = getTickCount();
<!---cfsavecontent.cfm --->
<cfset startTime = getTickCount()>
<cfset i=1>
<cfsetting enablecfoutputonly="true">
<cfsavecontent variable="s">
<cfloop condition="i LE stringLength"><!--- doing it this way to best emulate the for() loops in the other examples --->
<cfoutput>X</cfoutput>
<cfset i=i+1>
</cfloop>
</cfsavecontent>
<cfsetting enablecfoutputonly="false">
<cfset endTime = getTickCount()>
Generating a million-char string using the string.cfm method was not viable, so I instead tested with a magnitude of "5", creating 100k char strings. The results were as follows:
Test | Mean (ms) | |
---|---|---|
CF | Railo | |
string | 6300 | 6600 |
stringbuffer | 487 | 82 |
cfsavecontent | 263 | 48 |
So this is interesting in a coupla ways, isn't it?
- Don't use string concatenation for this sort of thing;
- Railo craps all over ColdFusion on the other methods;
- Surprisingly(?) <cfsavecontent> is the best approach here (if one is to consider performance alone, which one should not).
Test | Mean (ms) | |
---|---|---|
CF | Railo | |
string | 8 | 2 |
stringbuffer | 13 | 4 |
cfsavecontent | 8 | 2 |
Again, Railo is the better performer, but now the overhead of creating the StringBuffer and then coverting it to a string seems to be taking up a significant amount of the total time, so it's not a practical approach any more. <cfsavecontent> still competes with string concatenation though. I think, really, the conciseness of the code using the concatenation operator is more of a consideration than using <cfsavecontent> for string ops though.
Obviously with smaller magnitudes, the differences become even more inconsequential.
And that's me for the day. Enjoy your New Year's Eve if it's looming, or I hope your hangover is not so bad if you've already done it.
Cheers.
--
Adam