为什么List .Enumerator比我的实现更快?

由于各种大的性能优势(在我的情况下),我发现自己处于一个我必须推出自己的动态数组实现的位置。 但是,在为我的版本创建一个枚举器,并将效率与List使用的效率进行比较之后,我有点不知所措; List one比我的版本大约快30-40%,尽管它要复杂得多。

这是List枚举器实现的重要部分:

public struct Enumerator : IEnumerator, IDisposable, IEnumerator { private List list; private int index; private int version; private T current; internal Enumerator(List list) { this.list = list; this.index = 0; this.version = list._version; this.current = default(T); return; } public bool MoveNext() { List list; list = this.list; if (this.version != list._version) { goto Label_004A; } if (this.index >= list._size) { goto Label_004A; } this.current = list._items[this.index]; this.index += 1; return 1; Label_004A: return this.MoveNextRare(); } public T Current { get { return this.current; } } } 

这是我的准系统版本:

 internal struct DynamicArrayEnumerator : IEnumerator where T : class { private readonly T[] internalArray; private readonly int lastIndex; private int currentIndex; internal DynamicArrayEnumerator(DynamicArray dynamicArray) { internalArray = dynamicArray.internalArray; lastIndex = internalArray.Length - 1; currentIndex = -1; } public T Current { get { return internalArray[currentIndex]; } } public bool MoveNext() { return (++currentIndex <= lastIndex); } } 

我知道这是微优化,但我真的很想理解为什么List枚举器比我的快得多。 有任何想法吗? 谢谢!

编辑:按要求; DynamicArray类(相关部分):枚举器是一个内部类。

 public struct DynamicArray : IEnumerable where T : class { private T[] internalArray; private int itemCount; internal T[] Data { get { return internalArray; } } public int Count { get { return itemCount; } } public DynamicArray(int count) { this.internalArray = new T[count]; this.itemCount = 0; } public IEnumerator GetEnumerator() { return new DynamicArrayEnumerator(this); } IEnumerator IEnumerable.GetEnumerator() { return this.GetEnumerator(); } } 

至于我如何测试:

  List list = new List(1000000); DynamicArray dynamicArray = new DynamicArray(1000000); // Code for filling with data omitted. int numberOfRuns = 0; float p1Total = 0; float p2Total = 0; while (numberOfRuns  { int u = 0; foreach (BaseClass b in list) { if (bB > 100) // Some trivial task u++; } }); p1.ExecuteAndClock(); p1Total += p1.TotalElapsedTicks; PerformanceAnalyzer p2 = new PerformanceAnalyzer(() => { int u = 0; foreach (BaseClass b in dynamicArray) { if (bB > 100) // Some trivial task u++; } }); p2.ExecuteAndClock(); p2Total += p2.TotalElapsedTicks; numberOfRuns++; } Console.WriteLine("List enumeration: " + p1Total / totalRuns + "\n"); Console.WriteLine("Dynamic array enumeration: " + p2Total / totalRuns + "\n"); 

PerformanceAnalyzer类基本上启动一个秒表,执行提供的Action委托,然后停止秒表。

编辑2(对Ryan Gates的快速回答):有几个原因我想要自己动手,最重要的是我需要一个非常快的RemoveAt(int index)方法。

由于我不必担心在我的特定情况下列表元素的顺序,我可以避免.Net内置列表的方式:

 public void RemoveAt(int index) { T local; if (index = this._size) { goto Label_0042; } Array.Copy(this._items, index + 1, this._items, index, this._size - index); Label_0042: this._items[this._size] = default(T); this._version += 1; return; } 

而是使用以下内容:

 public void RemoveAt(int index) { // overwrites the element at the specified index with the last element in the array and decreases the item count. internalArray[index] = internalArray[itemCount]; itemCount--; } 

如果说长列表中的前1000个元素必须通过索引删除,那么在我的情况下可以节省大量的时间。

好的,除了基准测试问题之外,以下是如何使您的DynamicArray类更像List

 public DynamicArrayEnumerator GetEnumerator() { return new DynamicArrayEnumerator(this); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return this.GetEnumerator(); } 

现在, 知道它正在使用动态数组的代码可以使用DynamicArrayEnumerator进行迭代而无需任何装箱,也无需虚拟分派 。 这正是List所做的。 当类型以自定义方式实现模式时,编译器会注意到,并将使用所涉及的类型而不是接口。

使用您当前的代码,您无法从创建struct获益 – 因为您在GetEnumerator()中将其装箱。

尝试上述更改修复基准测试以延长工作时间。 我希望看到一个很大的不同。