3 回答

TA貢獻1877條經(jīng)驗 獲得超1個贊
這是我的原帖,引發(fā)了一些爭論...... 因為它錯了:
switch語句與if-else語句不同。每個案例必須是唯一的并且靜態(tài)評估。無論您有多少個案例,switch語句都會執(zhí)行一個恒定時間分支。if-else語句計算每個條件,直到找到一個為真。
實際上,C#switch語句并不總是一個恒定時間分支。
在某些情況下,編譯器將使用CIL開關(guān)語句,該語句確實是使用跳轉(zhuǎn)表的恒定時間分支。然而,在Ivan Hamilton指出的稀疏情況下,編譯器可能完全生成其他東西。
這實際上很容易通過編寫各種C#switch語句來驗證,一些稀疏,一些密集,并使用ildasm.exe工具查看生成的CIL。

TA貢獻1871條經(jīng)驗 獲得超13個贊
重要的是不要將C#switch語句與CIL開關(guān)指令混淆。
CIL開關(guān)是一個跳轉(zhuǎn)表,需要索引到一組跳轉(zhuǎn)地址。
這僅在C#開關(guān)的情況相鄰時才有用:
case 3: blah; break;case 4: blah; break;case 5: blah; break;
但如果不是這樣的話,幾乎沒用:
case 10: blah; break;case 200: blah; break;case 3000: blah; break;
(你需要一個表~3000個條目,只使用3個插槽)
對于非相鄰表達式,編譯器可能會開始執(zhí)行線性if-else-if-else檢查。
對于較大的非相鄰表達式集,編譯器可以從二叉樹搜索開始,最后是if-else-if-else最后幾個項。
對于包含相鄰項塊的表達式集,編譯器可以進行二叉樹搜索,最后是CIL開關(guān)。
這充滿了“mays”和“mights”,它依賴于編譯器(可能與Mono或Rotor不同)。
我使用相鄰的案例在我的機器上復(fù)制了你的結(jié)果:
執(zhí)行10路開關(guān)的總時間,10000次迭代(ms):
每10路開關(guān)25.1383 近似時間(ms):0.00251383執(zhí)行50路開關(guān)的總時間,10000次迭代(ms):
每50路開關(guān)的大約時間為26.593 (ms):0.0026593執(zhí)行5000路開關(guān)的總時間,10000次迭代(ms):23.7094
每5000路開關(guān)的近似時間(ms):0.00237094執(zhí)行50000路開關(guān)的總時間,10000次迭代(ms):20.0933
每50000路開關(guān)的近似時間(ms):0.00200933
然后我也使用了非相鄰的case表達式:
執(zhí)行10路開關(guān)的總時間,10000次迭代(ms):19.6189
每10路開關(guān)的近似時間(ms):0.00196189執(zhí)行500路開關(guān)的總時間,10000次迭代(ms):
每個500路開關(guān)的近似時間為19.1664 (ms):0.00191664執(zhí)行5000路開關(guān)的總時間,10000次迭代(ms):
每5000路開關(guān)的大約時間為19.5871 (ms):0.00195871不相鄰的50,000個案例切換語句將無法編譯。
“在'ConsoleApplication1.Program.Main(string [])'附近編譯表達式太長或太復(fù)雜
這里有趣的是,二叉樹搜索比CIL切換指令更快(可能不是統(tǒng)計上)。
Brian,你使用了“ 常量 ” 這個詞,從計算復(fù)雜性理論的角度來看,它具有非常明確的含義。雖然簡化的相鄰整數(shù)示例可以產(chǎn)生被認為是O(1)(常數(shù))的CIL,但稀疏示例是O(log n)(對數(shù)),聚類示例介于兩者之間,小例子是O(n)(線性) )。
這甚至不能解決Generic.Dictionary<string,int32>
可能會創(chuàng)建靜態(tài)的String情況,并且在首次使用時會遇到明確的開銷。這里的表現(xiàn)將取決于表現(xiàn)Generic.Dictionary
。
如果檢查C#語言規(guī)范(不是CIL規(guī)范),你會發(fā)現(xiàn)“15.7.2 switch語句”沒有提到“常量時間”或底層實現(xiàn)甚至使用CIL開關(guān)指令(要非常小心假設(shè)這樣的事情)。
在一天結(jié)束時,針對現(xiàn)代系統(tǒng)上的整數(shù)表達式的C#切換是亞微秒操作,通常不值得擔(dān)心。
當(dāng)然,這些時間將取決于機器和條件。我不會注意這些時序測試,我們所討論的微秒持續(xù)時間與正在運行的任何“真實”代碼相比相形見絀(并且您必須包含一些“真實代碼”,否則編譯器將優(yōu)化分支),或者系統(tǒng)中的抖動。我的答案基于使用IL DASM來檢查C#編譯器創(chuàng)建的CIL。當(dāng)然,這不是最終的,因為CPU運行的實際指令隨后由JIT創(chuàng)建。
我檢查了在我的x86機器上實際執(zhí)行的最終CPU指令,并且可以確認一個簡單的相鄰設(shè)置開關(guān),例如:
jmp ds:300025F0[eax*4]
二叉樹搜索滿滿的地方:
cmp ebx, 79Eh jg 3000352B cmp ebx, 654h jg 300032BB … cmp ebx, 0F82h jz 30005EEE
- 3 回答
- 0 關(guān)注
- 757 瀏覽
添加回答
舉報