<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://blogs.msdn.com/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>jaredpar's WebLog : Performance</title><link>http://blogs.msdn.com/jaredpar/archive/tags/Performance/default.aspx</link><description>Tags: Performance</description><dc:language>en-US</dc:language><generator>CommunityServer 2.1 SP1 (Build: 61025.2)</generator><item><title>Immutable vs. Mutable Collection Performance</title><link>http://blogs.msdn.com/jaredpar/archive/2009/04/06/immutable-vs-mutable-collection-performance.aspx</link><pubDate>Mon, 06 Apr 2009 15:00:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9532916</guid><dc:creator>Jared Parsons</dc:creator><slash:comments>6</slash:comments><comments>http://blogs.msdn.com/jaredpar/comments/9532916.aspx</comments><wfw:commentRss>http://blogs.msdn.com/jaredpar/commentrss.aspx?PostID=9532916</wfw:commentRss><wfw:comment>http://blogs.msdn.com/jaredpar/rsscomments.aspx?PostID=9532916</wfw:comment><description>&lt;p&gt;One argument I commonly hear against immutable collections is they are slow.&amp;#160; I’ve held the opposite belief for some time but shamefully had yet to look at actual numbers on the CLR.&amp;#160; Tonight I decided to change that by benchmarking one of &lt;a href="http://code.msdn.com/BclExtras"&gt;my immutable collections&lt;/a&gt; against a mutable collection in the BCL.&amp;#160; The goal is not to decide the overall best collection but instead to get a sense of how they perform relative to each other in certain scenarios.&lt;/p&gt;  &lt;p&gt;For the immutable version, I chose to use ImmutableCollection.&amp;#160; This class is a slight variation of Eric Lippert’s &lt;a href="http://blogs.msdn.com/ericlippert/archive/2008/02/12/immutability-in-c-part-eleven-a-working-double-ended-queue.aspx"&gt;Double Ended Queue&lt;/a&gt; implementation.&amp;#160; The core algorithm is the same but the style was changed to be more inline with other immutable collections I own. For the mutable class I chose to use the ever popular &lt;a href="http://msdn.microsoft.com/en-us/library/6sh2ey19.aspx"&gt;List&amp;lt;T&amp;gt;&lt;/a&gt; collection.&amp;#160; &lt;/p&gt;  &lt;p&gt;I chose to examine the following scenarios that I commonly use with collection style classes.&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Adding to the end of the collection &lt;/li&gt;    &lt;li&gt;Adding to the front of the collection &lt;/li&gt;    &lt;li&gt;Removing from the end of the collection &lt;/li&gt;    &lt;li&gt;Removing from the beginning of the collection &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Each scenario was run against collections of 100, 1000 and 10000 elements.&amp;#160; For each count, the run was executed 1000 times and the total and average time was calculated.&amp;#160; The full code for the benchmark is available at the end of this post.&amp;#160; &lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Looking at the data&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Now before I get into the results, please assume the usual caveats that come with any benchmark.&amp;#160; That is, approach it with a skeptical eye.&amp;#160; These scenarios are obviously not something I do &lt;strong&gt;exactly &lt;/strong&gt;in everyday programming (especially removing thousands of elements from the front of List&amp;lt;T&amp;gt;).&amp;#160; However they are representative of general operations that I do use.&amp;#160; Also I find it interesting to see how the collections perform relative to each other in extreme scenarios.&lt;/p&gt;  &lt;p&gt;Most of the results were unsurprising.&amp;#160; Remove from end is a very simple operation on a List&amp;lt;T&amp;gt;.&amp;#160; It comes down to a bounds check, decrementing an index and updating a couple of internal state variables.&amp;#160;&amp;#160; Removing the end of an immutable collection requires considerable updating of the internal structure.&amp;#160; It ends up being roughly 1 order of magnitude slower.&amp;#160;&amp;#160;&amp;#160; Adding to the end has similar implementation and numbers.&lt;/p&gt;  &lt;p&gt;Operations on the front of the list were significantly slower on List&amp;lt;T&amp;gt; than ImmutableCollection for suitably large collections.&amp;#160; This is unsurprising given that removal and insertion at the front of a List&amp;lt;T&amp;gt; requires all of the other elements in the underlying array to be shifted up or down.&amp;#160; This is a non-trivial operation and is evident in the benchmark.&amp;#160; &lt;/p&gt;  &lt;p&gt;The most interesting item however, is to look at how each collection scales.&amp;#160; In almost all scenarios, ImmutableCollection scaled very closely to the size of the input.&amp;#160; That is, an order of magnitude more input resulted in an order of magnitude of more time.&amp;#160; List&amp;lt;T&amp;gt; does not have that behavior for all scenarios.&amp;#160; Scenarios dealing with the front of the collection saw time rises faster relative to input size.&amp;#160; In fact there is a very dramatic jump in both front scenarios between 1000 and 1000 elements.&amp;#160; Each case resulted in roughly 2 orders of magnitude more time.&amp;#160; &lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Winner of each category … &lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Add to End: List&amp;lt;T&amp;gt; &lt;/li&gt;    &lt;li&gt;Add to Front: ImmutableCollection&amp;lt;T&amp;gt; &lt;/li&gt;    &lt;li&gt;Remove from End: List&amp;lt;T&amp;gt; &lt;/li&gt;    &lt;li&gt;Remove from Front: ImmutableCollection&amp;lt;T&amp;gt; &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;No single benchmark is definitive and this one won’t change that.&amp;#160; This benchmark says nothing about the general use of the two classes.&amp;#160; However it can provide some insight into these specific scenarios.&amp;#160; It also serves as some level of proof that immutable collections can have acceptable performance for these scenarios.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Data&lt;/strong&gt;&lt;/p&gt;  &lt;pre&gt;Add to End 100 Elements
       List: Total: 00:00:00.0060473 Average: 00:00:00.0000060
  Immutable: Total: 00:00:00.0267079 Average: 00:00:00.0000267
Add to End 1000 Elements
       List: Total: 00:00:00.0337505 Average: 00:00:00.0000337
  Immutable: Total: 00:00:00.2240444 Average: 00:00:00.0002240
Add to End 10000 Elements
       List: Total: 00:00:00.4266014 Average: 00:00:00.0004266
  Immutable: Total: 00:00:02.6715789 Average: 00:00:00.0026715
Add to Front 100 Elements
       List: Total: 00:00:00.0162186 Average: 00:00:00.0000162
  Immutable: Total: 00:00:00.0213764 Average: 00:00:00.0000213
Add to Front 1000 Elements
       List: Total: 00:00:00.4028523 Average: 00:00:00.0004028
  Immutable: Total: 00:00:00.2055935 Average: 00:00:00.0002055
Add to Front 10000 Elements
       List: Total: 00:00:38.5943722 Average: 00:00:00.0385943
  Immutable: Total: 00:00:02.6212590 Average: 00:00:00.0026212
Remove From End 100 Elements
       List: Total: 00:00:00.0031299 Average: 00:00:00.0000031
  Immutable: Total: 00:00:00.0213737 Average: 00:00:00.0000213
Remove From End 1000 Elements
       List: Total: 00:00:00.0187998 Average: 00:00:00.0000187
  Immutable: Total: 00:00:00.1623739 Average: 00:00:00.0001623
Remove From End 10000 Elements
       List: Total: 00:00:00.1773381 Average: 00:00:00.0001773
  Immutable: Total: 00:00:01.9615781 Average: 00:00:00.0019615
Remove From Front 100 Elements
       List: Total: 00:00:00.0142981 Average: 00:00:00.0000142
  Immutable: Total: 00:00:00.0192679 Average: 00:00:00.0000192
Remove From Front 1000 Elements
       List: Total: 00:00:00.4407993 Average: 00:00:00.0004407
  Immutable: Total: 00:00:00.1879243 Average: 00:00:00.0001879
Remove From Front 10000 Elements
       List: Total: 00:00:39.7832085 Average: 00:00:00.0397832
  Immutable: Total: 00:00:02.2451406 Average: 00:00:00.0022451&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;The Code&lt;/strong&gt;&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;public class &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Program &lt;/span&gt;{
    &lt;span style="color: blue"&gt;public static void &lt;/span&gt;ImmutableCollectionAddToEnd(&lt;span style="color: #2b91af"&gt;List&lt;/span&gt;&amp;lt;&lt;span style="color: blue"&gt;string&lt;/span&gt;&amp;gt; list) {
        &lt;span style="color: blue"&gt;var &lt;/span&gt;col = &lt;span style="color: #2b91af"&gt;ImmutableCollection&lt;/span&gt;&amp;lt;&lt;span style="color: blue"&gt;string&lt;/span&gt;&amp;gt;.Empty;
        &lt;span style="color: blue"&gt;foreach &lt;/span&gt;(&lt;span style="color: blue"&gt;var &lt;/span&gt;item &lt;span style="color: blue"&gt;in &lt;/span&gt;list) {
            col = col.AddBack(item);
        }
    }
    &lt;span style="color: blue"&gt;public static void &lt;/span&gt;ListAddToEnd(&lt;span style="color: #2b91af"&gt;List&lt;/span&gt;&amp;lt;&lt;span style="color: blue"&gt;string&lt;/span&gt;&amp;gt; list) {
        &lt;span style="color: blue"&gt;var &lt;/span&gt;col = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;List&lt;/span&gt;&amp;lt;&lt;span style="color: blue"&gt;string&lt;/span&gt;&amp;gt;();
        &lt;span style="color: blue"&gt;foreach &lt;/span&gt;(&lt;span style="color: blue"&gt;var &lt;/span&gt;item &lt;span style="color: blue"&gt;in &lt;/span&gt;list) {
            col.Add(item);
        }
    }
    &lt;span style="color: blue"&gt;public static void &lt;/span&gt;RunAddToEnd(&lt;span style="color: blue"&gt;int &lt;/span&gt;count) {
        &lt;span style="color: blue"&gt;var &lt;/span&gt;list = &lt;span style="color: #2b91af"&gt;Enumerable&lt;/span&gt;.Range(0, count).Select(x =&amp;gt; x.ToString()).ToList();
        &lt;span style="color: #2b91af"&gt;Console&lt;/span&gt;.WriteLine(&lt;span style="color: #a31515"&gt;&amp;quot;Add to End {0} Elements&amp;quot;&lt;/span&gt;, count);
        RunScenario(&lt;span style="color: #a31515"&gt;&amp;quot;List&amp;quot;&lt;/span&gt;, ListAddToEnd, () =&amp;gt; list);
        RunScenario(&lt;span style="color: #a31515"&gt;&amp;quot;Immutable&amp;quot;&lt;/span&gt;, ImmutableCollectionAddToEnd, () =&amp;gt; list);
    }
    &lt;span style="color: blue"&gt;public static void &lt;/span&gt;ImmutableCollectionAddToFront(&lt;span style="color: #2b91af"&gt;List&lt;/span&gt;&amp;lt;&lt;span style="color: blue"&gt;string&lt;/span&gt;&amp;gt; list) {
        &lt;span style="color: blue"&gt;var &lt;/span&gt;col = &lt;span style="color: #2b91af"&gt;ImmutableCollection&lt;/span&gt;&amp;lt;&lt;span style="color: blue"&gt;string&lt;/span&gt;&amp;gt;.Empty;
        &lt;span style="color: blue"&gt;foreach &lt;/span&gt;(&lt;span style="color: blue"&gt;var &lt;/span&gt;item &lt;span style="color: blue"&gt;in &lt;/span&gt;list) {
            col = col.AddFront(item);
        }
    }
    &lt;span style="color: blue"&gt;public static void &lt;/span&gt;ListAddToFront(&lt;span style="color: #2b91af"&gt;List&lt;/span&gt;&amp;lt;&lt;span style="color: blue"&gt;string&lt;/span&gt;&amp;gt; list) {
        &lt;span style="color: blue"&gt;var &lt;/span&gt;col = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;List&lt;/span&gt;&amp;lt;&lt;span style="color: blue"&gt;string&lt;/span&gt;&amp;gt;();
        &lt;span style="color: blue"&gt;foreach &lt;/span&gt;(&lt;span style="color: blue"&gt;var &lt;/span&gt;item &lt;span style="color: blue"&gt;in &lt;/span&gt;list) {
            col.Insert(0, item);
        }
    }
    &lt;span style="color: blue"&gt;public static void &lt;/span&gt;RunAddToFront(&lt;span style="color: blue"&gt;int &lt;/span&gt;count) {
        &lt;span style="color: blue"&gt;var &lt;/span&gt;list = &lt;span style="color: #2b91af"&gt;Enumerable&lt;/span&gt;.Range(0, count).Select(x =&amp;gt; x.ToString()).ToList();
        &lt;span style="color: #2b91af"&gt;Console&lt;/span&gt;.WriteLine(&lt;span style="color: #a31515"&gt;&amp;quot;Add to Front {0} Elements&amp;quot;&lt;/span&gt;, count);
        RunScenario(&lt;span style="color: #a31515"&gt;&amp;quot;List&amp;quot;&lt;/span&gt;, ListAddToFront, () =&amp;gt; list);
        RunScenario(&lt;span style="color: #a31515"&gt;&amp;quot;Immutable&amp;quot;&lt;/span&gt;, ImmutableCollectionAddToFront, () =&amp;gt; list);
    }
    &lt;span style="color: blue"&gt;public static void &lt;/span&gt;ImmutableCollectionRemoveFromEnd(&lt;span style="color: #2b91af"&gt;ImmutableCollection&lt;/span&gt;&amp;lt;&lt;span style="color: blue"&gt;string&lt;/span&gt;&amp;gt; col) {
        &lt;span style="color: blue"&gt;while &lt;/span&gt;(!col.IsEmpty) {
            col = col.RemoveBack();
        }
    }
    &lt;span style="color: blue"&gt;public static void &lt;/span&gt;ListRemoveFromEnd(&lt;span style="color: #2b91af"&gt;List&lt;/span&gt;&amp;lt;&lt;span style="color: blue"&gt;string&lt;/span&gt;&amp;gt; list) {
        &lt;span style="color: blue"&gt;while &lt;/span&gt;(list.Count &amp;gt; 0) {
            list.RemoveAt(list.Count - 1);
        }
    }
    &lt;span style="color: blue"&gt;public static void &lt;/span&gt;RunRemoveFromEnd(&lt;span style="color: blue"&gt;int &lt;/span&gt;count) {
        &lt;span style="color: #2b91af"&gt;Func&lt;/span&gt;&amp;lt;&lt;span style="color: #2b91af"&gt;List&lt;/span&gt;&amp;lt;&lt;span style="color: blue"&gt;string&lt;/span&gt;&amp;gt;&amp;gt; listInputFunc = () =&amp;gt; &lt;span style="color: #2b91af"&gt;Enumerable&lt;/span&gt;.Range(0, count).Select(x =&amp;gt; x.ToString()).ToList();
        &lt;span style="color: #2b91af"&gt;Func&lt;/span&gt;&amp;lt;&lt;span style="color: #2b91af"&gt;ImmutableCollection&lt;/span&gt;&amp;lt;&lt;span style="color: blue"&gt;string&lt;/span&gt;&amp;gt;&amp;gt; colInputFunc = () =&amp;gt; &lt;span style="color: #2b91af"&gt;ImmutableCollection&lt;/span&gt;.Create(listInputFunc());
        &lt;span style="color: #2b91af"&gt;Console&lt;/span&gt;.WriteLine(&lt;span style="color: #a31515"&gt;&amp;quot;Remove From End {0} Elements&amp;quot;&lt;/span&gt;, count);
        RunScenario(&lt;span style="color: #a31515"&gt;&amp;quot;List&amp;quot;&lt;/span&gt;, ListRemoveFromEnd, listInputFunc);
        RunScenario(&lt;span style="color: #a31515"&gt;&amp;quot;Immutable&amp;quot;&lt;/span&gt;, ImmutableCollectionRemoveFromEnd, colInputFunc);
    }
    &lt;span style="color: blue"&gt;public static void &lt;/span&gt;ImmutableCollectionRemoveFromFront(&lt;span style="color: #2b91af"&gt;ImmutableCollection&lt;/span&gt;&amp;lt;&lt;span style="color: blue"&gt;string&lt;/span&gt;&amp;gt; col) {
        &lt;span style="color: blue"&gt;while &lt;/span&gt;(!col.IsEmpty) {
            col = col.RemoveFront();
        }
    }
    &lt;span style="color: blue"&gt;public static void &lt;/span&gt;ListRemoveFromFront(&lt;span style="color: #2b91af"&gt;List&lt;/span&gt;&amp;lt;&lt;span style="color: blue"&gt;string&lt;/span&gt;&amp;gt; col) {
        &lt;span style="color: blue"&gt;while &lt;/span&gt;(col.Count &amp;gt; 0) {
            col.RemoveAt(0);
        }
    }
    &lt;span style="color: blue"&gt;public static void &lt;/span&gt;RunRemoveFromFront(&lt;span style="color: blue"&gt;int &lt;/span&gt;count) {
        &lt;span style="color: #2b91af"&gt;Func&lt;/span&gt;&amp;lt;&lt;span style="color: #2b91af"&gt;List&lt;/span&gt;&amp;lt;&lt;span style="color: blue"&gt;string&lt;/span&gt;&amp;gt;&amp;gt; listInputFunc = () =&amp;gt; &lt;span style="color: #2b91af"&gt;Enumerable&lt;/span&gt;.Range(0, count).Select(x =&amp;gt; x.ToString()).ToList();
        &lt;span style="color: #2b91af"&gt;Func&lt;/span&gt;&amp;lt;&lt;span style="color: #2b91af"&gt;ImmutableCollection&lt;/span&gt;&amp;lt;&lt;span style="color: blue"&gt;string&lt;/span&gt;&amp;gt;&amp;gt; colInputFunc = () =&amp;gt; &lt;span style="color: #2b91af"&gt;ImmutableCollection&lt;/span&gt;.Create(listInputFunc());
        &lt;span style="color: #2b91af"&gt;Console&lt;/span&gt;.WriteLine(&lt;span style="color: #a31515"&gt;&amp;quot;Remove From Front {0} Elements&amp;quot;&lt;/span&gt;, count);
        RunScenario(&lt;span style="color: #a31515"&gt;&amp;quot;List&amp;quot;&lt;/span&gt;, ListRemoveFromFront, listInputFunc);
        RunScenario(&lt;span style="color: #a31515"&gt;&amp;quot;Immutable&amp;quot;&lt;/span&gt;, ImmutableCollectionRemoveFromFront, colInputFunc);
    }
    &lt;span style="color: blue"&gt;public static void &lt;/span&gt;RunScenario&amp;lt;T&amp;gt;(&lt;span style="color: blue"&gt;string &lt;/span&gt;description, &lt;span style="color: #2b91af"&gt;Action&lt;/span&gt;&amp;lt;T&amp;gt; del, &lt;span style="color: #2b91af"&gt;Func&lt;/span&gt;&amp;lt;T&amp;gt; getInputFunc) {
        &lt;span style="color: green"&gt;// Run once to jit
        &lt;/span&gt;del(getInputFunc());
        &lt;span style="color: blue"&gt;const int &lt;/span&gt;times = 1000;
        &lt;span style="color: blue"&gt;var &lt;/span&gt;total = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;TimeSpan&lt;/span&gt;();
        &lt;span style="color: blue"&gt;for &lt;/span&gt;(&lt;span style="color: blue"&gt;var &lt;/span&gt;i = 0; i &amp;lt; times; i++) {
            &lt;span style="color: green"&gt;// get the input outside the timer so input creation is not calculated 
            &lt;/span&gt;&lt;span style="color: blue"&gt;var &lt;/span&gt;input = getInputFunc();
            &lt;span style="color: blue"&gt;var &lt;/span&gt;watch = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Stopwatch&lt;/span&gt;();
            watch.Start();
            del(input);
            watch.Stop();
            total += watch.Elapsed;
        }
        &lt;span style="color: blue"&gt;var &lt;/span&gt;average = &lt;span style="color: #2b91af"&gt;TimeSpan&lt;/span&gt;.FromTicks(total.Ticks / times);
        &lt;span style="color: #2b91af"&gt;Console&lt;/span&gt;.WriteLine(&lt;span style="color: #a31515"&gt;&amp;quot;{0,11}: Total: {1} Average: {2}&amp;quot;&lt;/span&gt;, description, total, average);
    }
    &lt;span style="color: blue"&gt;static void &lt;/span&gt;Main(&lt;span style="color: blue"&gt;string&lt;/span&gt;[] args) {
        &lt;span style="color: blue"&gt;var &lt;/span&gt;list = &lt;span style="color: blue"&gt;new int&lt;/span&gt;[] { 100, 1000, 10000 };
        list.ForEach(RunAddToEnd);
        list.ForEach(RunAddToFront);
        list.ForEach(RunRemoveFromEnd);
        list.ForEach(RunRemoveFromFront);
    }
}&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9532916" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/jaredpar/archive/tags/C_2300_/default.aspx">C#</category><category domain="http://blogs.msdn.com/jaredpar/archive/tags/Immutable/default.aspx">Immutable</category><category domain="http://blogs.msdn.com/jaredpar/archive/tags/Performance/default.aspx">Performance</category></item></channel></rss>