簡體   English   中英

切換案例或std :: map的效率更高

[英]What is more efficient a switch case or an std::map

我在這里考慮令牌化器。
每個標記在解析器內調用不同的函數。
什么更有效:

  • std :: functions / boost :: functions的映射
  • 開關盒

我建議閱讀switch()與查找表? 來自Joel on Software。 特別是,這種反應很有趣:

“人們浪費時間試圖優化最不重要的事情的典型例子。”

是的,不是。 在VM中,您通常會調用每個函數都很少的微小函數。 這不是因為每個函數的前導碼和清理例程經常占執行時間的重要百分比而對你造成傷害的呼叫/返回。 這已經被研究過死亡,特別是那些已經實施了線程解釋器的人。

在虛擬機中,存儲計算地址以進行調用的查找表通常優先於交換機。 (直接線程,或“標簽為值”。直接調用存儲在查找表中的標簽地址)這是因為它允許在某些條件下減少分支錯誤預測 ,這在長流水線CPU中非常昂貴(它強制沖洗管道)。 但是,它使代碼不那么便攜。

此問題已在VM社區中進行了廣泛討論,如果您想了解更多相關信息,我建議您在此字段中查找學者論文。 Ertl&Gregg在2001年寫了一篇關於這個主題的精彩文章, 關於現代建築的高效虛擬機解釋器的行為

但如上所述,我很確定這些細節與您的代碼無關。 這些都是小細節,你不應該過分關注它。 Python解釋器使用開關,因為他們認為它使代碼更具可讀性。 你為什么不選擇最舒服的用法? 性能影響相當小,您現在最好關注代碼可讀性;)

編輯 :如果重要,使用哈希表將始終比查找表慢。 對於查找表,可以使用枚舉類型作為“鍵”,並使用單個間接跳轉檢索值。 這是一個單獨的裝配操作。 O(1)。 哈希表查找首先需要計算哈希值,然后檢索值,這樣更昂貴。

使用存儲函數地址的數組,並使用枚舉值訪問是很好的。 但是使用哈希表來做同樣的事情會增加一個重要的開銷

總之,我們有:

  • cost(Hash_table)>> cost(direct_lookup_table)
  • cost(direct_lookup_table)〜= cost(switch)如果編譯器將開關轉換為查找表。
  • cost(switch)>> cost(direct_lookup_table)(O(N)vs O(1))如果你的編譯器不轉換開關並使用條件,但我想不出任何編譯器這樣做。
  • 但內聯直接線程使代碼可讀性降低。

隨着Visual Studio 2008附帶的STL Map將為每個函數調用提供O(log(n)),因為它隱藏了下面的樹結構。 使用現代編譯器(取決於實現),一個switch語句將為您提供O(1),編譯器將其轉換為某種查找表。 所以一般來說,切換速度更快。

但是 ,請考慮以下事實:

map和switch之間的區別在於:Map可以動態構建,而switch也不能。 Map可以包含任意類型作為鍵,而switch僅限於c ++ Primitive類型(char,int,enum等...)。

順便說一句,你可以使用哈希映射來實現幾乎O(1)調度(但是,根據哈希表的實現,在最壞的情況下它有時可能是O(n))。 盡管如此,開關仍然會更快。

編輯

我寫這篇文章的目的只是為了好玩和討論的問題

我可以為您推薦一個很好的優化,但這取決於您的語言的性質以及您是否可以期待如何使用您的語言。

編寫代碼時:將令牌分為兩組,一組經常使用非常高,另一組經常使用低。 您還可以對經常使用的高級令牌進行排序。 對於高頻率令牌,您可以編寫一個if-else系列,其中常用的頻率最高。 對於經常使用的低,你寫一個switch語句。

我們的想法是使用CPU分支預測,以便甚至避免另一個間接級別(假設if語句中的條件檢查幾乎是無成本的)。 在大多數情況下,CPU將選擇正確的分支而沒有任何間接級別。 然而,他們將是少數情況下分支將去錯誤的地方。 根據你的語言的性質,統計它可以提供更好的表現。

編輯 :由於下面的一些評論,更改句子告訴編譯器將總是轉換為LUT。

你對“有效”的定義是什么? 如果你的意思更快,那么你可能應該分析一些測試代碼以獲得明確的答案。 如果您正在使用靈活且易於擴展的代碼,那么請自己幫忙並使用映射方法。 其他一切都只是過早優化......

就像yossi1981所說的那樣,交換機可以優化為快速查找表但不能保證,每個編譯器都有其他算法來確定是將連接實現為連續if還是快速查找表,或者兩者的組合。

要獲得快速切換,您的值應符合以下規則:它們應該是連續的,例如0,1,2,3,4。 您可以保留一些值,但是0,1,2,34,43之類的東西極不可能被優化。

問題實際上是:在您的應用程序中表現如此重要嗎? 並且,從文件動態加載其值的地圖是否更具可讀性和可維護性,而不是跨越多頁代碼的巨大語句?

你沒有說出你的代幣是什么類型的。 如果它們不是整數,則沒有選擇 - 開關僅適用於整數類型。

C ++標准沒有說明其要求的性能,只是功能應該存在。

除非你說明你正在談論哪種實現,否則這些關於哪種更好,更快或更有效的問題都是沒有意義的。 例如,某個JavaScript實現版本中的字符串處理非常糟糕,但您無法將其推斷為相關標准的功能。

我甚至會說無論實現如何都沒關系,因為switchstd::map提供的功能不同(盡管有重疊)。

在我看來,這種微觀優化幾乎從來都不是必需的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM