Why is this List<>.IndexOf code so much faster than the List[i] and manual compare?

前端 未结 3 1768
无人共我
无人共我 2021-02-06 02:30

I\'m running AQTime on this piece of code, I found that .IndexOf takes 16% of the time vs close to 80% for the other piece... They appear to use the same IsEqual and other rout

3条回答
  •  你的背包
    2021-02-06 02:56

    Normally, before you access an array element, it checks to make sure that the index is >= 0 and < length -- so that you don't read or overwrite memory that doesn't belong to you. Among other things, it eliminates a slew of severe security flaws called buffer overflows.

    Needless to say, that impedes performance if you have very little code within your loop. To lessen this problem, the JIT compiler optimizes for-loops of the form for (i = 0; i < array.Length; i++) { array[i]; } -- that is, any loop that accesses all the indices of an array from 0 to length - 1. It omits the bounds checking for this case. (The optimization fails if you access things like array[i + 1], for the reason that you might step over the bounds.)

    Unfortunately this only works with arrays, not with List<>s. So your latter code will not be optimized.

    But since a List<> internally contains an array, and List.IndexOf() uses a loop to access each value in the array directly, it can be optimized.

    By the way, it's better to say for (int i = 0; i < array.Length; i++) { } than it is to say int length = array.Length; for(int i = 0; i < length; i++) { } -- because it can't be sure that length really is the length of the array.

    Edit: looking at the IndexOf code using Reflector, the loop will indeed optimize, but as the other people here have mentioned, it calls Equals() -- which requires a vtable lookup and various sanity checks. So in this case, IndexOf might in fact be slower when you're not running it with a profiler.

    The disassembled code:

    internal virtual int IndexOf(T[] array, T value, int startIndex, int count)
    {
        int num = startIndex + count;
        for (int i = startIndex; i < num; i++)
        {
            if (this.Equals(array[i], value))
            {
                return i;
            }
        }
        return -1;
    }
    

提交回复
热议问题