簡體   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