1

I was reading about how collections such as Built-in Arrays and Lists differ from each other, and noticed that built-in arrays are a lot faster than Lists (up to 7 times as faster in certain situations).

So my question is, If I use built in arrays that I do not fill completely but instead have a max value, and use a counter int to keep track of the size, will it be significantly faster than using Lists?

The reason it matters is I have a multiplayer game that I built the server for myself in Node.js from the ground up, and am using websockets-sharp as the library for the client, and am seeing some lag due to the collections I have to modify and check in my update functions (using Lists, Stacks, Dictionary, and Queues) and am wondering byte[] array would increase performance.

P.S. Here are is where I got the information from about built in array performance vs System.Collections:

http://answers.unity3d.com/questions/38479/is-listt-as-fast-to-access-as-a-standard-array.html

Performance differences... so dramatic?

http://wiki.unity3d.com/index.php/Choosing_the_right_collection_type

Community
  • 1
  • 1
daniel metlitski
  • 747
  • 3
  • 11
  • 23
  • Totally depends on how your app adds and retrieves data. Write once? Read-only? Random access? Append only? Random insert? –  Feb 17 '17 at 02:27
  • I would be using the built in array in the same way I would use the Lists currently which includes looping over it, modifying it's contents with adding and removing items. – daniel metlitski Feb 17 '17 at 02:33
  • I want to answer this but need more details. For your question about Dictionary Vs List, how are you planning to use these? The usage matters in other to compare the two. – Programmer Feb 17 '17 at 02:35
  • I will post that in one separate question @Programmer – daniel metlitski Feb 17 '17 at 02:36
  • How do you "loop over" `List`? Do you use `foreach`? Be aware that doing so creates an enumerator object that impacts the GC which is noticeable in .NET < 4.0 such as the release of Mono used by Unity and also for XNA devs –  Feb 17 '17 at 02:39
  • Side note: it may be good idea to show example where "arrays are 7x faster than List" - it is somewhat hard to see where one can get such slowdown. – Alexei Levenkov Feb 17 '17 at 02:39
  • @AlexeiLevenkov Source is here: http://answers.unity3d.com/questions/38479/is-listt-as-fast-to-access-as-a-standard-array.html – daniel metlitski Feb 17 '17 at 02:43
  • @MickyD I use for loops not foreach, I am aware of the performance implications of using foreach – daniel metlitski Feb 17 '17 at 02:43
  • @MickyD the enumerator of list is a structure that foreach accesses on the stack without GC pressure unless the list is accessed through an interface. It still has costs over index-based loops, but not that cost. It is one place array wins though since (again, if accessed directly instead of through an interface) the compiler turns foreach on that into the equivalent indexing loop, and skips the bounds tests. – Jon Hanna Feb 17 '17 at 02:51
  • @JonHanna Note that question is Mono/Unity specific - when I believe you talk about regular desktop C#/JIT. – Alexei Levenkov Feb 17 '17 at 03:34
  • @JonHanna _"the enumerator of list is a structure"_ - not entirely. _"[In versions of Unity prior to 5.5, a foreach loop iterating over anything other than an array generates garbage each time the loop terminates. This is due to boxing that happens behind the scenes. A System.Object is allocated on the heap when the loop begins and disposed of when the loop terminates. This problem was fixed in Unity 5.5.](https://unity3d.com/learn/tutorials/topics/performance-optimization/optimizing-garbage-collection-unity-games)"_. Unity 5.5 is 30 Nov 2016 so the fix is quite recent –  Feb 17 '17 at 05:27
  • @MickyD ooh. Yuck. – Jon Hanna Feb 17 '17 at 10:16
  • @JonHanna haha agreed :) –  Feb 17 '17 at 11:20
  • @MickyD and if its still got the ways that `List.Enumerator` being a mutable struct can lead to some snafus, that's the worse of both worlds. – Jon Hanna Feb 17 '17 at 11:53

2 Answers2

3

If I use built in arrays that I do not fill completely but instead have a max value, and use a counter int to keep track of the size, will it be significantly faster than using Lists?

Yes.

I've done experiment with Unity in the past and doing this is totally fine for large amount of items that needs to be looped over every frame such as image processing.

I once made an app that stream HQ Image over the network. It was easy to make with a List but after I switched to Array, the number of frames I received per second increased. It also got ride of memory allocation.

The only down side to using Array is that you have to allocate large amount of memory to make sure that it is enough to hold your items. You also have to check if the current item you want to put in the array can fit. If not, you have to create new array with bigger size, then copy old data to the new one.

Unity's blog also has a post that shows the performance different between using Array and List to improve the Update() function. It is really a big performance increase and the Array is about 5x faster than List in that experiment.

These are the rules I set for myself when working Unity and it still remians to be true even today:

1.If you need to store large items(200k and above) that requires you loop through them every frame, use array and a simple int value that you can use to determine the length of the array.

2.If this is just items about the size of 5,000 and runs only once in a while then use List.

I modified this code to run in Unity and below is the result.

Array/for: 6726ms (-1295415896)

List/for: 15803ms (-1295415896)

Array/foreach: 8511ms (-1295415896)

List/foreach: 42689ms (-1295415896)

The difference is very important in Unity unlike a normal C# Application.

void Start()
{
    List<int> list = new List<int>(6000000);
    for (int i = 0; i < 6000000; i++)
    {
        list.Add(UnityEngine.Random.Range(1, 10));
    }
    int[] arr = list.ToArray();

    int chk = 0;
    Stopwatch watch = Stopwatch.StartNew();
    for (int rpt = 0; rpt < 100; rpt++)
    {
        int len = list.Count;
        for (int i = 0; i < len; i++)
        {
            chk += list[i];
        }
    }
    watch.Stop();
    UnityEngine.Debug.Log(String.Format("List/for: {0}ms ({1})", watch.ElapsedMilliseconds, chk));

    chk = 0;
    watch = Stopwatch.StartNew();
    for (int rpt = 0; rpt < 100; rpt++)
    {
        int len = arr.Length;
        for (int i = 0; i < len; i++)
        {
            chk += arr[i];
        }
    }
    watch.Stop();
    UnityEngine.Debug.Log(String.Format("Array/for: {0}ms ({1})", watch.ElapsedMilliseconds, chk));

    chk = 0;
    watch = Stopwatch.StartNew();
    for (int rpt = 0; rpt < 100; rpt++)
    {
        foreach (int i in list)
        {
            chk += i;
        }
    }
    watch.Stop();
    UnityEngine.Debug.Log(String.Format("List/foreach: {0}ms ({1})", watch.ElapsedMilliseconds, chk));

    chk = 0;
    watch = Stopwatch.StartNew();
    for (int rpt = 0; rpt < 100; rpt++)
    {
        foreach (int i in arr)
        {
            chk += i;
        }
    }
    watch.Stop();
    UnityEngine.Debug.Log(String.Format("Array/foreach: {0}ms ({1})", watch.ElapsedMilliseconds, chk));
}
Community
  • 1
  • 1
Programmer
  • 121,791
  • 22
  • 236
  • 328
  • 1
    Side note: "It also got rid of memory allocation" is probably the actual reason of your real code being much faster (as even 2x difference in cost of access is likely drowned in cost of processing each item)... And there is no reason why you could not obtain similar benefits by simply reusing pre-allocated list with `List.Clear`... – Alexei Levenkov Feb 17 '17 at 03:26
  • @AlexeiLevenkov Yes, I was re-using the `List` and also used `List.Clear()` too. Only adding to the List seems to be allocating memory sometimes. Accessing its value does not. It allocates until the List size is more than the size of the Image I was sending. The problem is that my image size is always changing sizes. – Programmer Feb 17 '17 at 03:40
  • Sometimes the image size goes up, sometimes it goes down and that causes the `List` allocate for a while. It stops at some point though but the performance difference is always there even after it stops allocation memory. I know that I can specify the `List` size on creation to stop the allocation part but if you have to specify the size on time then why not use `Array`? Also, please take a look at the Unity blog I linked in the answer that shows the `Array` vs `List` performance difference. – Programmer Feb 17 '17 at 03:43
2

In the overlap of functionality between arrays and lists the fact that lists implemented by wrapping an array means that we would almost always expect arrays to be faster, and that's before considering that directly accessing the array can allow some compiler and jitter optimisations, too.

That said, there's now more that you have to do, if you are going to do something list provided and arrays don't. If your doing that isn't as efficient as the code in list, you're just going to make things slower. Even if done perfectly you might e.g. not be able to have code that lets the jitter skip the bounds check (because you are leaving some space at the end of the array for example) which means that the real performance won't be as good as a benchmark where the jitter could do that).

All the more so when it comes to dictionary, which you also mention as arrays do not provide the same hash-based O(1) lookup.

Really, to switch to arrays from lists in the interest of performance you want to study the code of List (the source is available) understand where the costs are, and then consider how those costs affect your given usages. That'll be a guide to where switching will gain, lose, break, or just be a waste of time.

Jon Hanna
  • 110,372
  • 10
  • 146
  • 251