大家看到这样的标题也许会在想,try catch肯定会影响性能的,但是其实并没有很直接的证据表明trycatch会影响系统的性能,尤其是在托管的环境下,今天就用实际的代码来证明下在不同情况下,代码运行的时间指标。
.NET中的异常捕获以及处理的机制都是try catch finally块来完成的,作用分别是异常的检测 捕获以及处理。
每个类都会跟一个异常表(exception table) 每一个try catch都会在这张表里面添加记录,每一个记录都有四个值:try catch的开始地址 结束地址 异常处理的起始位 异常类名称。当代码抛出异常的时候,首先会拿着抛出的位置到异常表里面按顺序去查找是由有可以合适的catch(例如查看位置是不是处于任何一个的开始和结束位置之间),如果有,则跑到异常的开始位置开始处理,如果没有在原地return,并且copy异常的引用,返回给父调用方,继续查找父的异常表,以此类推。如果无异常发生,只需要遍历finlly项,那几乎跟正常的无区别,如果发生了异常,只不过多了一个遍历exception table然后在遍历finlly项。记住:trycatch引起的反应只是监控与触发,这一部分的消耗微乎其微
如下实例:
public static void TryCatch()
{
try
{
Convert.ToInt32("Try");
}
catch (FormatException ex1)
{
Console.WriteLine(ex1.Message);
}
catch (NullReferenceException ex2)
{
Console.WriteLine(ex2.Message);
}
finally
{
Console.WriteLine("Finally");
}
}
IL代码:
<pre class="csharp" name="code">.method public hidebysig static void TryCatch() cil managed
{
// 代码大小 69 (0x45)
.maxstack 1
.locals init ([0] class [mscorlib]System.FormatException ex1,
[1] class [mscorlib]System.NullReferenceException ex2)
IL_0000: nop
.try
{
.try
{
IL_0001: nop
IL_0002: ldstr "Try"
IL_0007: call int32 [mscorlib]System.Convert::ToInt32(string)
IL_000c: pop
IL_000d: nop
IL_000e: leave.s IL_0032
} // end .try
catch [mscorlib]System.FormatException
{
IL_0010: stloc.0
IL_0011: nop
IL_0012: ldloc.0
IL_0013: callvirt instance string [mscorlib]System.Exception::get_Message()
IL_0018: call void [mscorlib]System.Console::WriteLine(string)
IL_001d: nop
IL_001e: nop
IL_001f: leave.s IL_0032
} // end handler
catch [mscorlib]System.NullReferenceException
{
IL_0021: stloc.1
IL_0022: nop
IL_0023: ldloc.1
IL_0024: callvirt instance string [mscorlib]System.Exception::get_Message()
IL_0029: call void [mscorlib]System.Console::WriteLine(string)
IL_002e: nop
IL_002f: nop
IL_0030: leave.s IL_0032
} // end handler
IL_0032: nop
IL_0033: leave.s IL_0043
} // end .try
finally
{
IL_0035: nop
IL_0036: ldstr "Finally"
IL_003b: call void [mscorlib]System.Console::WriteLine(string)
IL_0040: nop
IL_0041: nop
IL_0042: endfinally
} // end handler
IL_0043: nop
IL_0044: ret
} // end of method Program::TryCatch
然后我们比较一下正常的情况下与加了try catch的之间的区别:
static void Main(string[] args)
{
//Stopwatch stop1 = new Stopwatch();
//stop1.Start();
//for (int i = 0; i < NUM_TESTS; i++)
//{
// tryInLoop();
//}
//stop1.Stop();
//Console.WriteLine(stop1.ElapsedMilliseconds);
Stopwatch stop2 = new Stopwatch();
stop2.Start();
for (int i = 0; i < NUM_TESTS; i++)
{
TryOutLoop();
}
stop2.Stop();
Console.WriteLine(stop2.ElapsedMilliseconds);
Stopwatch stop3 = new Stopwatch();
stop3.Start();
for (int i = 0; i < NUM_TESTS; i++)
{
InLoop();
}
stop3.Stop();
Console.WriteLine(stop3.ElapsedMilliseconds);
Console.ReadLine();
}
//public static int tryInLoop()
//{
// int count = 0;
// for (int i = 0; i < ITERATIONS; i++)
// {
// try
// {
// count += 1;
// }
// catch (NotFiniteNumberException ex)
// {
// return 0;
// }
// }
// return count;
//}
public static int InLoop()
{
int count = 0;
for (int i = 0; i < ITERATIONS; i++)
{
count += 1;
}
return count;
}
public static int TryOutLoop()
{
int count = 0;
try
{
for (int i = 0; i < ITERATIONS; i++)
{
count+=1;
}
return count;
}
catch (NotFiniteNumberException ex)
{ return 0; }
}
对比的结果:
由此可见基本上是没有差别的,另外有些人对trycatch在for里面与外面的性能也有怀疑,认为放在里面的性能会差些,真的么?取消注释上面的代码,再看看结果
我们发现性能的影响基本上可以忽略不计的,除非你是对性能有苛刻的要求。针对是在循环里面进行trycatch还是外面,主要是一个代码习惯的问题,还有就是你是否有需要for的循环执行完毕的选择,并未有很大的影响
谢谢