請看下面兩段:
第一種方式:
MemoryStream stream = new MemoryStream();
string text = "aasasdfasdfad;sas;fkqeworpkqwefkasdjfasdjf"; byte[] buff = System.Text.ASCIIEncoding.ASCII.GetBytes(text); stream.Write(buff, 0, buff.Length); stream.Flush(); stream.Close(); stream.Dispose();
第二種方式:
string text = "aasasdfasdfad;sas;fkqeworpkqwefkasdjfasdjf"; using (MemoryStream stream = new MemoryStream()) { byte[] buff = System.Text.ASCIIEncoding.ASCII.GetBytes(text); stream.Write(buff, 0, buff.Length); stream.Flush(); stream.Close(); }
不僅僅是我,估計一個老鳥程序員,大都會選擇方法二,雖然方法一和方法二實現相同的功能,但是方法二帶着套比較保險,即便我們失手,不會制造出垃圾來(這話聽着怪怪的,能理解我在說什么就好)。之后,我在做一些消息處理機制的接收、處理、分發測試中,發現使用using關鍵字和不用using關鍵字,效率有着很大差異,不使用using關鍵字效率明顯偏高,MQ隊列占用明顯偏小,這是為什么呢?答案馬上揭曉。
以下是通過反匯編工具所得的中間語言(IL)
.method private hidebysig static void Main(string[] args) cil managed { .entrypoint // 代碼大小 65 (0x41) .maxstack 4 .locals init ([0] string text, [1] class [mscorlib]System.IO.MemoryStream 'stream', [2] uint8[] buff) IL_0000: nop IL_0001: ldstr "aasasdfasdfad;sas;fkqeworpkqwefkasdjfasdjf" IL_0006: stloc.0 IL_0007: newobj instance void [mscorlib]System.IO.MemoryStream::.ctor() IL_000c: stloc.1 IL_000d: call class [mscorlib]System.Text.Encoding [mscorlib]System.Text.Encoding::get_ASCII() IL_0012: ldloc.0 IL_0013: callvirt instance uint8[] [mscorlib]System.Text.Encoding::GetBytes(string) IL_0018: stloc.2 IL_0019: ldloc.1 IL_001a: ldloc.2 IL_001b: ldc.i4.0 IL_001c: ldloc.2 IL_001d: ldlen IL_001e: conv.i4 IL_001f: callvirt instance void [mscorlib]System.IO.Stream::Write(uint8[], int32, int32) IL_0024: nop IL_0025: ldloc.1 IL_0026: callvirt instance void [mscorlib]System.IO.Stream::Flush() IL_002b: nop IL_002c: ldloc.1 IL_002d: callvirt instance void [mscorlib]System.IO.Stream::Close() IL_0032: nop IL_0033: ldloc.1 IL_0034: callvirt instance void [mscorlib]System.IO.Stream::Dispose() IL_0039: nop IL_0040: ret } // end of method Program::Main
以上是方法一,所得中間語言,看起來非常干凈、流暢。下面看看方法二的:
.method private hidebysig static void Main(string[] args) cil managed { .entrypoint // 代碼大小 79 (0x4f) .maxstack 4 .locals init ([0] string text, [1] class [mscorlib]System.IO.MemoryStream 'stream', [2] uint8[] buff, [3] bool CS$4$0000) IL_0000: nop IL_0001: ldstr "aasasdfasdfad;sas;fkqeworpkqwefkasdjfasdjf" IL_0006: stloc.0 IL_0007: newobj instance void [mscorlib]System.IO.MemoryStream::.ctor() IL_000c: stloc.1 .try { IL_000d: nop IL_000e: call class [mscorlib]System.Text.Encoding [mscorlib]System.Text.Encoding::get_ASCII() IL_0013: ldloc.0 IL_0014: callvirt instance uint8[] [mscorlib]System.Text.Encoding::GetBytes(string) IL_0019: stloc.2 IL_001a: ldloc.1 IL_001b: ldloc.2 IL_001c: ldc.i4.0 IL_001d: ldloc.2 IL_001e: ldlen IL_001f: conv.i4 IL_0020: callvirt instance void [mscorlib]System.IO.Stream::Write(uint8[], int32, int32) IL_0025: nop IL_0026: ldloc.1 IL_0027: callvirt instance void [mscorlib]System.IO.Stream::Flush() IL_002c: nop IL_002d: ldloc.1 IL_002e: callvirt instance void [mscorlib]System.IO.Stream::Close() IL_0033: nop IL_0034: nop IL_0035: leave.s IL_0047 } // end .try finally { IL_0037: ldloc.1 IL_0038: ldnull IL_0039: ceq IL_003b: stloc.3 IL_003c: ldloc.3 IL_003d: brtrue.s IL_0046 IL_003f: ldloc.1 IL_0040: callvirt instance void [mscorlib]System.IDisposable::Dispose() IL_0045: nop IL_0046: endfinally } // end handler IL_0047: pop IL_0048: ret } // end of method Program::Main
第二段IL中間紅色部分即為不同
[3] bool CS$4$0000) IL_000d: nop 停止幾個時鍾周期 IL_000d: nop IL_0035: leave.s IL_0047 退出受保護的代碼區域,無條件將控制轉移到目標指令 IL_0038: ldnull 將空引用(O 類型)推送到計算堆棧上 IL_0039: ceq 比較兩個值。如果這兩個值相等,則將整數值 1 (int32) 推送到計算堆棧上;否則,將 0 (int32) 推送到計算堆棧上 IL_003b: stloc.3 從計算堆棧的頂部彈出當前值並將其存儲到索引 3 處的局部變量列表中 IL_003c: ldloc.3 將索引 3 處的局部變量加載到計算堆棧上 IL_003d: brtrue.s IL_0046 如果 value 為 true、非空或非零,則將控制轉移到目標指令 IL_003f: ldloc.1 將索引 1 處的局部變量加載到計算堆棧上 IL_0045: nop IL_0046: endfinally 將控制從異常塊的 fault 或 finally 子句轉移回公共語言結構 (CLI) 異常處理程序
但是剛剛我們也提到了,雖然方法一和方法二實現相同的功能,但是方法二帶着套比較保險,即便我們失手,不會制造出垃圾來。即使是你忘記使用.close()、.dispose()方法釋放資源,using還是會自動幫你處理好你遺忘的的壞事。
所以在一般不要求高效開發中,盡量使用using,但是在處理高並發、海量數據等等情況下,盡量不要讓using出現。
提示:
try..catch有一定的代碼優化能力,少量代碼測試,try..catch可能更優