Note that there are some explanatory texts on larger screens.

plurals
  1. POWhy is array item assignment degrading C# program performance?
    text
    copied!<h3>Summary</h3> <p>While processing a large text file, I came across the following (unexpected) performance degradation that I can't explain. My objectives for this question are:</p> <ul> <li>Understand what causes the slowdown described below</li> <li>Find out how to initialize large non-primitive arrays quickly</li> </ul> <h3>The Problem</h3> <ul> <li>Array contains non-primitive reference items <ul> <li>Not <code>int[]</code> but <code>MyComplexType[]</code></li> <li><code>MyComplexType</code> is a class, not a struct</li> <li><code>MyComplexType</code> contains some <code>string</code> properties</li> </ul></li> <li>Array is pre-allocated</li> <li>Array is large</li> <li>If an item is created and used without being assigned to the array, program is fast</li> <li>If an item is created and then <strong>assigned to an array item</strong>, program <strong>slows down significantly</strong> <ul> <li>I expected array item assignment to be a simple <em>reference assignment</em>, but this does not seem to the the case based on my results for my test program below</li> </ul></li> </ul> <h3>Test program</h3> <p>Consider the following <code>C#</code> program:</p> <pre><code>namespace Test { public static class Program { // Simple data structure private sealed class Item { public Item(int i) { this.Name = "Hello " + i; //this.Name = "Hello"; //this.Name = null; } public readonly string Name; } // Test program public static void Main() { const int length = 1000000; var items = new Item[length]; // Create one million items but don't assign to array var w = System.Diagnostics.Stopwatch.StartNew(); for (var i = 0; i &lt; length; i++) { var item = new Item(i); if (!string.IsNullOrEmpty(item.Name)) // reference the item and its Name property { items[i] = null; // do not remember the item } } System.Console.Error.WriteLine("Without assignment: " + w.Elapsed); // Create one million items and assign to array w.Restart(); for (var i = 0; i &lt; length; i++) { var item = new Item(i); if (!string.IsNullOrEmpty(item.Name)) // reference the item and its Name property { items[i] = item; // remember the item } } System.Console.Error.WriteLine(" With assignment: " + w.Elapsed); } } } </code></pre> <p>It contains two almost-identical loops. Each loop creates one million instances of <code>Item</code> class. First loop uses the created item and then throws away the reference (not persisting it in the <code>items</code> array). Second loop uses the created item and then stores the reference in the <code>items</code> array. Array item assignment is the only difference between the loops.</p> <h3>My Results</h3> <ul> <li><p>When I run <code>Release</code> build (optimizations turned on) on my machine, I get the following results:</p> <pre><code>Without assignment: 00:00:00.2193348 With assignment: 00:00:00.8819170 </code></pre> <p>Loop with array assignment is significantly slower than the one without assignment (~4x slower). </p></li> <li><p>If I change <code>Item</code> constructor to assign a constant string to <code>Name</code> property:</p> <pre><code>public Item(int i) { //this.Name = "Hello " + i; this.Name = "Hello"; //this.Name = null; } </code></pre> <p>I get the following results:</p> <pre><code>Without assignment: 00:00:00.0228067 With assignment: 00:00:00.0718317 </code></pre> <p>Loop with assignment is still ~3x slower than the one without</p></li> <li><p>Finally if I assign <code>null</code> to the <code>Name</code> property:</p> <pre><code>public Item(int i) { //this.Name = "Hello " + i; //this.Name = "Hello"; this.Name = null; } </code></pre> <p>I get the following result:</p> <pre><code>Without assignment: 00:00:00.0146696 With assignment: 00:00:00.0105369 </code></pre> <p>Once no string is allocated, the version without assignment is finally slightly slower (I assume because all those instances are released for garbage collection)</p></li> </ul> <h3>Questions</h3> <ul> <li><p>Why is array item assignment slowing the test program so much?</p></li> <li><p>Is there an attribute/language construct/etc that will speed up the assignment?</p></li> </ul> <p>PS: I tried investigating the slowdown using dotTrace, but it was inconclusive. One thing I saw was a lot more string copying and garbage collection overhead in the loop with assignment than in the loop without assignment (even though I expected the reverse).</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload