2010-11-23 79 views
3

下午好,IEnumerable的<T>和「收益率回報」的性能問題

我寫一個簡單的詞法分析器基本上是的this one修改後的版本。獲得每個令牌後,我需要進行輕微的修改並重新分析以重新檢查它的類型。另外,當然,在詞法分析之後,我需要重新使用整個令牌列表來對其進行「解析」。我的問題是,如果在詞法分析器中使用IEnumerable<Token>yield return語句可以使整個程序的性能變得更慢......使用List<Token>來迭代構建列表並使用正常的return語句會更好嗎?迭代IEnumerable/List怎麼樣?哪一個更快?

非常感謝。

+2

嘗試對代碼進行基準測試...不要犧牲可感知的性能改進的可讀性 – 2010-11-23 14:43:55

回答

5

你問的是錯誤的問題,你應該更擔心正則表達式的成本。枚舉令牌只是其中的一小部分,在優化代碼方面沒有任何意義,它可以提高一倍,但只能將程序性能提高1%。

編寫代碼,對其進行配置,您將知道如何處理版本2.鑑於這些類型的工具在'人類時間'運行(當程序需要20毫秒時需要兩倍的時間才能察覺到差異),最可能的結果是「沒有任何需要完成」。

+0

感謝漢斯。但是,你有什麼建議來提高Regex的性能呢? – Miguel 2010-11-23 15:07:19

3

它可能會對的某些性能產生影響 - 但它也允許迭代器被構建爲懶惰。

就我個人而言,我會以最易讀的方式編寫代碼並測量它的性能 - 然後開始擔心微型優化這類事情。以一種方式進行測試,以另一種方式進行測試,通過使用最高性能的解決方案以及您實際獲得多少速度來查看丟失了多少可讀性(如果有)。

注意,有以遍歷已知通過一個IEnumerable<T>恰好由List<T>被實現爲List<T>型VS迭代的表達非常輕微的性能益處,因爲List<T>實現使用一個可變的結構中的迭代器本身.. 。如果你使用更高的抽象層,基本上你會得到一個盒裝值,但在這種特殊情況下,我幾乎肯定會使用正確的抽象概念來改善性能。

1

IEnumerable和yield return語句被轉換成一個GetEnumator()並在IL代碼中實現一個枚舉器。

儘管在枚舉過程中爲返回的每個標記做了一些額外的工作,收益回報有其優點,但我會堅持列表創建並返回列表,因爲它會導致更少的方法調用,因此應該更快。

+0

是什麼讓您認爲將有更少的方法調用?據推測,每個項目都會有一個Add ...的調用,這在迭代器版本中不需要。在這兩種情況下,都會有相同數量的MoveNext()/當前調用。 – 2010-11-23 14:46:27

0

到現在爲止,我敢肯定,你會看到你試圖過早地進行優化,這是,根據許多,the root of all evil.

但是,如果你真的想加快這,正則表達式似乎一個昂貴的方式來做到這一點。每次執行Regex.Match()時,都會再次掃描字符串,這會導致至少與令牌相同的掃描次數。

如果你知道定義一個標記的邊界(例如'{'和'}'),你可以掃描一次字符串來構建標記的枚舉(使用yield或list,我不認爲這會有很大的不同)。調用者然後可以重建字符串,查找值以替換標記。

當然,這隻適用於簡單的「搜索和替換」類型的令牌。更復雜的需要更復雜的東西,比如正則表達式。也許你可以擴展TokenDefinition來指定匹配是簡單匹配還是正則匹配。這將減少執行的正則表達式的數量,但仍然保持所需的靈活性。