繁体   English   中英

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

[英]Fastest way to iterate over a stack in c#

我觉得使用 GetEnumerator() 和转换 IEnumerator.Current 很昂贵。 有什么更好的建议吗?

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

经过思考:
通用堆栈会是一个更好的主意,这样就不需要演员表了吗?

Stack<T> (使用 foreach)确实可以挽救演员阵容,但实际上拳击在宏伟计划中并不是那么糟糕 如果您有性能问题,我怀疑这是您可以增加很多价值的领域。 使用分析器,并专注于实际问题 - 否则为时过早。

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

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

如果您需要堆栈的功能(与列表或其他一些集合类型相关),那么是的,请使用通用堆栈。 这将加快速度,因为编译器将在运行时跳过转换(因为它在编译时是 garunteed)。

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

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

您是否做过任何基准测试,或者它们只是直觉?

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

  1. 重新设计代码,以便不需要循环
  2. 找到一个更快的循环结构。 (我会推荐泛型,即使它没有那么重要。再次,做基准测试)。

编辑:

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

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

如果迭代变量的类型为 T,则枚举泛型IEnumerable<T>IEnumerator<T>不会创建强制转换,所以是的,在大多数情况下使用泛型会更快,但泛型有一些非常微妙的问题,尤其是与值类型一起使用时。

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

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

var enumerator = stack.GetEnumerator();

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

就 CPU 基准测试而言,这可能并不比 foreach 快,但 foreach 可能会出现意外的分配峰值,这最终会“降低”应用程序的性能。

创建枚举器的另一种方法是使用 ToArray 方法,然后遍历数组。 堆栈迭代器在检查堆栈是否已被修改时会产生一些轻微的开销,而对数组的迭代会很快。 但是,首先当然有创建数组的开销。 正如垫子所说,您应该对替代品进行基准测试。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM