【问题标题】:Fastest way to iterate over a stack in c#在 c# 中迭代​​堆栈的最快方法
【发布时间】:2008-10-31 09:02:54
【问题描述】:

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

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

经过深思熟虑:
通用堆栈会是一个更好的主意,这样就不需要强制转换了吗?

【问题讨论】:

  • 它们都将是相同的......使用 valuetypes 时,铸造只是有点慢。根据使用情况,我怀疑它会对性能产生很大影响。

标签: c# optimization stack


【解决方案1】:

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

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

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

【讨论】:

    【解决方案2】:

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

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

    1. 重新设计代码,这样就不需要循环了
    2. 找到更快的循环结构。 (我会推荐泛型,即使它并不重要。再次,做基准测试)。

    编辑:

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

    【讨论】:

    • 是的,现在只是一种感觉。我将运行一些基准测试并查看。谢谢
    【解决方案3】:

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

    Stack<MyClass> stacky = new Stack<MyClass>();
    
    foreach (MyClass item in stacky)
    {
        // this is as fast as you're going to get.
    }
    

    【讨论】:

      【解决方案4】:

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

      【讨论】:

        【解决方案5】:

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

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

        【讨论】:

          【解决方案6】:

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

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

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

          【讨论】:

            【解决方案7】:

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

            【讨论】:

            • 使用“ToArray”非常昂贵...在您开始迭代之前创建新对象的方式会造成巨大的性能损失。
            • 你确定它很贵吗?你量过吗?
            猜你喜欢
            • 2023-02-06
            • 2019-04-08
            • 2023-04-11
            • 1970-01-01
            • 1970-01-01
            • 2015-01-06
            • 2014-12-02
            • 2012-03-03
            • 2018-10-07
            相关资源
            最近更新 更多