7

Consider the following code:

using System;
using System.Collections.Generic;
using System.Diagnostics;

namespace ListAllocationPerformance
{
    class Program
    {
        const int count = 100000000;

        public static object Memory { get; private set; }

        static void Main(string[] args)
        {
            Console.WriteLine(string.Format("count: {0}", count));
            MeasureFunction(FillListWithoutAllocation, "without allocation");
            MeasureFunction(FillListWithAllocation, "with allocation");
            MeasureFunction(FillArray, "array");
            MeasureFunction(FillUnmanagedArray, "unsafe array");
            string input = Console.ReadLine();
        }

        static void MeasureFunction(Action function, string name)
        {
            Stopwatch stopwatch = new Stopwatch();
            stopwatch.Start();
            function();
            stopwatch.Stop();
            Console.WriteLine(string.Format("Function {0} finished after \t {1}ms", name, stopwatch.ElapsedMilliseconds, count));
        }

        static void FillListWithoutAllocation()
        {
            List<int> list = new List<int>();
            for (int i = 0; i < count; i++) list.Add(i);
        }

        static void FillListWithAllocation()
        {
            List<int> list = new List<int>(count);
            for (int i = 0; i < count; i++) list.Add(i);
        }

        static void FillArray()
        {
            int[] array = new int[count];
            for (int i = 0; i < count; i++) array[i] = i;
        }

        static void FillUnmanagedArray()
        {
            unsafe
            {
                int[] array = new int[count];
                fixed(int* ptr = array)

                for (int i = 0; i < count; i++) *ptr = i;
            }
        }
    }
}

The result of the release-built is stunning:

count: 100000000
Function without allocation finished after       871ms
Function with allocation finished after          684ms
Function array finished after                    168ms
Function unsafe array finished after              91ms

The array outperforms even the pre-allocated list by far! I thought that the list was basically an array under the hood -- but how come that the results differ so much?

user2033412
  • 1,950
  • 2
  • 27
  • 47
  • 3
    @MANIKANDANNAGALAKSHMI That question answers "which one is faster" but does not issue the "why". This question provides the "which one is faster" as context and asks **why**. – cbr Jan 09 '17 at 12:55
  • 2
    A List is a wrapper around an array, and of course this wrapper costs time. But it's only a 'big difference' in an artificially small sample. Start doing something real inside that loop and the difference drops quickly. – H H Jan 09 '17 at 12:56
  • 2
    @MANIKANDANNAGALAKSHMI -- Agree with cubrr. A possible answer here would be a link to an answer under that question (if there is one that not only demonstrates which is faster -- as that question asks -- but goes on to explain why) and then a summary of the substantive info from that answer. – rory.ap Jan 09 '17 at 12:56
  • @Juharr Yeah - I just deleted my comment, because I checked the source, and you're right :) [Source](https://referencesource.microsoft.com/#mscorlib/system/collections/generic/list.cs,eb66b6616c6fd4ef). – RB. Jan 09 '17 at 12:57
  • I have to add that the accepted answer to the _"array vs.list performance issue [duplicate]"_ question does at least attempt to answer your question, user2033412. – cbr Jan 09 '17 at 12:58
  • 1
    Lists implement a heavier foot print with a ton of extensible methods (Add, Remove, CopyTo, etc), a collection [] does not. – Mike Jan 09 '17 at 12:59
  • 4
    The most direct answer to the 'why' is [this one](http://stackoverflow.com/a/465236/60761), it's the elimination of boundschecking. – H H Jan 09 '17 at 13:00
  • 1
    by the way hundred million is not small number. so arrays are not _much_ faster than lists ;) – M.kazem Akhgary Jan 09 '17 at 13:05
  • A single call is *not* sufficient to draw any conclusions. You should perform *many* tests and analyze the results. You may find for example, that the first test is always slower, or that your code doesn't take memory allocation/deallocation into account. Use a library like BenchmarkDotNet to get some meaningful statistics – Panagiotis Kanavos Jan 09 '17 at 13:17
  • Yeah, there isn't a large difference between your list results and your array results given the large number of iterations. The question is: is it exponentially worse -- which doesn't appear to be the case. – rory.ap Jan 09 '17 at 13:17
  • It is a factor of four (!) slower which is definitely significant in my eyes. – user2033412 Jan 09 '17 at 13:19
  • @user2033412 -- It's a factor of 4 of a very small amount of time. It's a linear relationship, i.e. there will probably be 400 ms or whatever the difference is not matter how many iterations you have, which is just inherent because of the list setup overhead. My point is, if it were an exponential difference, i.e. if the gap widened the more iterations you have, then that would be a problem. – rory.ap Jan 09 '17 at 13:26
  • @Mmcgowa3 how many methods a type has does not really impact on performance, but rather what those types do. – Jon Hanna Jan 09 '17 at 13:41
  • A more direct comparison here would be to prefill an array and then assign through it's setter. It would still be slower than assigning to an array but likely not quite as much. – Jon Hanna Jan 09 '17 at 13:43
  • @JonHanna Actually if you are serializing and desterilizing objects the amount of properties, and methods on that type make a huge difference in performance. – Mike Jan 09 '17 at 13:47
  • @Mmcgowa3 which isn't relevant here. – Jon Hanna Jan 09 '17 at 13:50
  • @rory.ap it is _not_ a constant time-offset. I tried again for one billion points and the _factor_ remains constantly four. It does not diminish with a growing number of iterations. – user2033412 Jan 09 '17 at 17:12
  • @user2033412 -- I didn't say constant, I said linear. If the factor were 36 instead of 4 with one billion points, then it would be exponential. – rory.ap Jan 09 '17 at 17:33
  • @rory.ap: The linear factor is what bothers me. Why is it that big? – user2033412 Jan 10 '17 at 15:15

0 Answers0