Performance crime: Concat

Quiz time

Brainstorm to begin with – which code is faster and why:

var language = new object();
var version = new object();

var a = string.Concat(itemId, language, "¤", version);
var b = string.Concat(itemId, language.ToString(), "¤", version.ToString());

Answer

Despite both lines look super familiar, a is 30% slower due to an overload with params being picked:

As you might have guessed (from previous post), params force an array allocation (which I treat as crime):

Calling ToString explicitly cuts out one third of wall clock time (1076 vs 767):

Does the code look familiar?

The sample code looks to be a suitable candidate to act as a cache key for an item (in fact, it is). Not only it produces a new string on each go, but also forces brute-force string over direct by-field comparison. We can easily fix those flaws and cook a faster version:

struct Key: IEquatable<Key>
 {
   private readonly ID _id;
   private readonly Language _language;
   private readonly Version _version;

   public Key(ID id, Language language, Version version)
    {
      _id = id;
      _language = language;
      _version = version;
     }
...
public static bool operator ==(Key a, Key b) => Equals(a._id, b._id) && Equals(a._version, b._version) && Equals(a._language, b._language);

The struct based-key uses by-field comparison and does not need allocations resulting in 4 times faster execution:

Summary

Joining strings to build a cache key might be four times as slow as doing it right with structs. You’ll tax system users with ~50ms on each page request (real-life numbers).

On the one hand, 1/20 of a second sounds very little.

On the other hand, the delay is brought by a few lines of code, whereas enterprise-level frameworks have huge code bases with non-zero chances having only one non-optimal code.

One thought on “Performance crime: Concat

  1. I am curious, if there could be any way to measure it, what percentage of the performance difference is related to passing arguments by reference (object) vs. value types (string/struct/etc.).

    Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: