My Calendar generation code is slow. How do I improve it?
I just read somewhere that AppendFormat() can be slower than simple Append() calls. Being shocked by reading this, I decided to investigate.

For 1,000,000 empty events the times required are:


With AppendFormat: 9297 ticks
Without AppendFormat: 8268 ticks


That is a considerable difference of 11%!

I'm guessing this is due to the lookup of the arguments and such. It would be nice if AppendFormat() would be recompiled to Append() calls only by default.

This is the code:

    /// &lt;summary&gt;
    /// Creates a calendar json string.
    /// &lt;/summary&gt;
    /// &lt;returns&gt;&lt;/returns&gt;
    public string ToFullCalendarJsonStringFaster()
    {
        StringBuilder sb = new StringBuilder();

        sb.Append( "[" );

        int count = Events.Count;
        int i = 0;

        foreach ( Event eventItem in Events )
        {
            sb.Append( "{" );

            sb.Append("\"title\":\"");
            sb.Append(eventItem.Title);
            sb.Append("\",");
            sb.Append("\"allDay\":\"");
            sb.Append(eventItem.AllDay);
            sb.Append("\",");

            if ( eventItem.AllDay )
            {
                // My test never comes here, so I left it out.
            }
            else
            {
                sb.Append("\"start\":\"");
                sb.Append(eventItem.Start.ToString("yyyy-MM-dd"));
                sb.Append("T");
                sb.Append(eventItem.Start.ToString("HH:mm:ss"));
                sb.Append("\",");

                sb.Append("\"end\":\"");
                sb.Append(eventItem.End.ToString("yyyy-MM-dd"));
                sb.Append("T");
                sb.Append(eventItem.End.ToString("HH:mm:ss"));
                sb.Append("\",");
            }
            sb.Append("\"url\":\"");
            sb.Append(eventItem.URL);
            sb.Append("\"");
            sb.Append( "}" );

            i++;

            if ( i &lt; count )
            {
                sb.Append( "," );
            }
        }

        sb.Append( "]" );

        return sb.ToString();
    }


By also applying Snowbear's earlier replies:


Using yyyy-MM-ddTHH:mm:ss as format strings, gives an extra speed difference of 5%
Preallocating StringBuilder size, gives an extra speed difference of 6%


In total, after applying all changes, the code is 22% faster. :)

Bottomline is, there probably isn't a 'magic' solution which can make it go instant with so many events, but you can improve the speed considerably. I suggest you run the processing on a BackgroundWorker.



... this is getting even more ridiculous. Changing the date formatting to the following:

//sb.Append(eventItem.Start.ToString( "yyyy-MM-ddTHH:mm:ss" ) );
sb.Append(eventItem.Start.Year);
sb.Append("-");
sb.Append(eventItem.Start.Month);
sb.Append("-");
sb.Append(eventItem.Start.Day);
sb.Append("T");
sb.Append(eventItem.Start.Hour);
sb.Append(":");
sb.Append(eventItem.Start.Minute);
sb.Append(":");
sb.Append(eventItem.Start.Second);
sb.Append("\",");


... gives another speed increase and makes it 34% faster in total. Might slow down 
again if you need more specific formatting.



Beware: this last update is probably erronous. I asked a question about proper usage of PLINQ.

I haven't used Parallel LINQ (PLINQ) yet. But this seemed a nice use for it. After replacing the for by:

Events.AsParallel().AsOrdered().ForAll( eventItem =&gt;
{
    ...
} );    


I get a total speed increase of 43%, again 9% faster. :) This is on a dual core processor. PC's with more cores should perform better. I don't know how PLINQ works exactly, but I would think it could work even faster if one iteration doesn't need to wait on another. The StringBuilder and i are exposed as closures. Anyone got any better approaches than ForAll()?