Note that there are some explanatory texts on larger screens.

plurals
  1. POWhy are multi-dimensional arrays in .NET slower than normal arrays?
    primarykey
    data
    text
    <p><strong>Edit:</strong> I apologize everybody. I used the term "jagged array" when I actually meant to say "multi-dimensional array" (as can be seen in my example below). I apologize for using the incorrect name. I actually found jagged arrays to be faster than multi-dimensional ones! I have added my measurements for jagged arrays.</p> <p>I was trying to use a <del>jagged</del> multi-dimensional array today, when I noticed that it's performance is not as I would have expected. Using a single-dimensional array and manually calculating indices was much faster (almost two times) than using a 2D array. I wrote a test using <code>1024*1024</code> arrays (initialized to random values), for 1000 iterations, and I got the following results on my machine:</p> <pre><code>sum(double[], int): 2738 ms (100%) sum(double[,]): 5019 ms (183%) sum(double[][]): 2540 ms ( 93%) </code></pre> <p>This is my test code:</p> <pre><code>public static double sum(double[] d, int l1) { // assuming the array is rectangular double sum = 0; int l2 = d.Length / l1; for (int i = 0; i &lt; l1; ++i) for (int j = 0; j &lt; l2; ++j) sum += d[i * l2 + j]; return sum; } public static double sum(double[,] d) { double sum = 0; int l1 = d.GetLength(0); int l2 = d.GetLength(1); for (int i = 0; i &lt; l1; ++i) for (int j = 0; j &lt; l2; ++j) sum += d[i, j]; return sum; } public static double sum(double[][] d) { double sum = 0; for (int i = 0; i &lt; d.Length; ++i) for (int j = 0; j &lt; d[i].Length; ++j) sum += d[i][j]; return sum; } public static void Main() { Random random = new Random(); const int l1 = 1024, l2 = 1024; double[ ] d1 = new double[l1 * l2]; double[,] d2 = new double[l1 , l2]; double[][] d3 = new double[l1][]; for (int i = 0; i &lt; l1; ++i) { d3[i] = new double[l2]; for (int j = 0; j &lt; l2; ++j) d3[i][j] = d2[i, j] = d1[i * l2 + j] = random.NextDouble(); } // const int iterations = 1000; TestTime(sum, d1, l1, iterations); TestTime(sum, d2, iterations); TestTime(sum, d3, iterations); } </code></pre> <p>Further investigation showed that the IL for the second method is 23% larger than that of the first method. (Code size 68 vs 52.) This is mostly due to calls to <code>System.Array::GetLength(int)</code>. The compiler also emits calls to <code>Array::Get</code> for the <del>jagged</del> multi-dimensional array, whereas it simply calls <code>ldelem</code> for the simple array.</p> <p>So I am wondering, why is access through multi-dimensional arrays slower than normal arrays? I would have assumed the compiler (or JIT) would do something similar to what I did in my first method, but this was not actually the case.</p> <p>Could you plese help me understand why this is happening the way it is?</p> <hr> <p><strong>Update:</strong> Following Henk Holterman's suggestion, here is the implementation of <code>TestTime</code>:</p> <pre><code>public static void TestTime&lt;T, TR&gt;(Func&lt;T, TR&gt; action, T obj, int iterations) { Stopwatch stopwatch = Stopwatch.StartNew(); for (int i = 0; i &lt; iterations; ++i) action(obj); Console.WriteLine(action.Method.Name + " took " + stopwatch.Elapsed); } public static void TestTime&lt;T1, T2, TR&gt;(Func&lt;T1, T2, TR&gt; action, T1 obj1, T2 obj2, int iterations) { Stopwatch stopwatch = Stopwatch.StartNew(); for (int i = 0; i &lt; iterations; ++i) action(obj1, obj2); Console.WriteLine(action.Method.Name + " took " + stopwatch.Elapsed); } </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

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