在c#中迭代堆栈的最快方法

时间:2008-10-31 09:02:55

标签: c# optimization stack

我觉得使用GetEnumerator()并投射IEnumerator.Current是很昂贵的。有什么更好的建议吗?

如果它提供具有更好性能的类似功能,我愿意使用不同的数据结构。

思考后:
泛型堆栈是否更好,以便不需要强制转换?

7 个答案:

答案 0 :(得分:14)

Stack<T>(使用foreach)确实可以保存演员表,但实际上是在{$ 3}}中装箱。如果您遇到性能问题,我怀疑这是您可以增加很多价值的领域。使用分析器,并专注于实际问题 - 否则这是不成熟的。

请注意,如果您只想读取一次数据(即您很乐意使用堆栈),那么可能更快(避免了枚举器的开销); YMMV。

    Stack<T> stack = null;
    while (stack.Count > 0)
    {
        T value = stack.Pop();
        // process value
    }

答案 1 :(得分:6)

你做过任何基准测试,还是只是直觉?

如果您认为大部分处理时间都花在循环堆栈上,那么您应该对其进行基准测试,并确保情况确实如此。如果是,您有几个选择。

  1. 重新设计代码,以便不需要循环
  2. 找到更快的循环结构。 (我会推荐仿制药,即使它没那么重要。再次,做基准测试。)
  3. 编辑:

    当您尝试在列表中进行查找或匹配两个列表或类似列表时,可能不需要的循环示例。如果循环需要很长时间,请查看将列表放入二叉树或哈希映射是否有意义。可能存在创建它们的初始成本,但是如果重新设计代码,则可以通过稍后进行O(1)查找来获得该代码。

答案 2 :(得分:5)

是的,使用通用堆栈将节省演员阵容。

答案 3 :(得分:4)

如果您需要Stack的功能(与List或其他一些colleciton类型相关),那么是的,使用通用堆栈。这会加快速度,因为编译器会在运行时跳过转换(因为它在编译时很流行)。

Stack<MyClass> stacky = new Stack<MyClass>();

foreach (MyClass item in stacky)
{
    // this is as fast as you're going to get.
}

答案 4 :(得分:2)

如果迭代变量是T类型,那么

枚举泛型IEnumerable<T>IEnumerator<T>并不会创建强制转换,所以在大多数情况下使用泛型会更快,但是泛型有一些非常微妙的问题,特别是当与值类型一起使用时。

Rico Mariani(微软性能架构师)有一些帖子详细介绍了差异和基础

答案 5 :(得分:1)

就速度而言,有多个变量,取决于上下文。例如,在像C#这样的自动内存管理代码库中,您可以获得分配峰值,这可能会影响游戏等帧速率。你可以为这个而不是foreach做一个很好的优化是一个带有while循环的枚举器:

var enumerator = stack.GetEnumerator();

while(enumerator.MoveNext ()) {
  // do stuff with enumerator value using enumerator.Current
  enumerator.Current = blah
}

就CPU基准而言,这可能不比foreach快,但foreach可能会出现意外的分配峰值,最终可能会减慢&#34;你的申请表现。

答案 6 :(得分:0)

创建枚举器的另一种方法是使用ToArray方法,然后迭代数组。堆栈迭代器会导致一些轻微的开销,用于检查堆栈是否已被修改,而对阵列的迭代将很快。但是,当然首先要创建数组的开销。正如垫子所说,你应该对备选方案进行基准测试。