当不抛出异常时,是否尝试/捕获块会损害性能?

在与微软员工进行代码审查期间,我们遇到了try{}块中的大部分代码。 她和一位IT代表表示,这可能会影响代码的性能。 事实上,他们建议大部分代码应该在try / catch块之外,并且只应检查重要的部分。 微软员工补充说,即将发布的白皮书警告不正确的try / catch块。

我环顾四周,发现它会影响优化,但它似乎只适用于在范围之间共享变量的情况。

我并不是在询问代码的可维护性,或者甚至处理正确的例外情况(无疑,这些代码需要重新分解)。 我也没有提到使用异常进行流量控制,这在大多数情况下显然是错误的。 这些是重要的问题(有些更重要),但不是这里的重点。

当不抛出异常时try / catch块如何影响性能?

编辑:我添加一个赏金。 有一些有趣的回应,但我想获得更多的意见。


核实。

static public void Main(string[] args)
{
    Stopwatch w = new Stopwatch();
    double d = 0;

    w.Start();

    for (int i = 0; i < 10000000; i++)
    {
        try
        {
            d = Math.Sin(1);
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.ToString());
        }
    }

    w.Stop();
    Console.WriteLine(w.Elapsed);
    w.Reset();
    w.Start();

    for (int i = 0; i < 10000000; i++)
    {
        d = Math.Sin(1);
    }

    w.Stop();
    Console.WriteLine(w.Elapsed);
}

输出:

00:00:00.4269033  // with try/catch
00:00:00.4260383  // without.

以毫秒为单位:

449
416

新代码:

for (int j = 0; j < 10; j++)
{
    Stopwatch w = new Stopwatch();
    double d = 0;
    w.Start();

    for (int i = 0; i < 10000000; i++)
    {
        try
        {
            d = Math.Sin(d);
        }

        catch (Exception ex)
        {
            Console.WriteLine(ex.ToString());
        }

        finally
        {
            d = Math.Sin(d);
        }
    }

    w.Stop();
    Console.Write("   try/catch/finally: ");
    Console.WriteLine(w.ElapsedMilliseconds);
    w.Reset();
    d = 0;
    w.Start();

    for (int i = 0; i < 10000000; i++)
    {
        d = Math.Sin(d);
        d = Math.Sin(d);
    }

    w.Stop();
    Console.Write("No try/catch/finally: ");
    Console.WriteLine(w.ElapsedMilliseconds);
    Console.WriteLine();
}

新结果:

   try/catch/finally: 382
No try/catch/finally: 332

   try/catch/finally: 375
No try/catch/finally: 332

   try/catch/finally: 376
No try/catch/finally: 333

   try/catch/finally: 375
No try/catch/finally: 330

   try/catch/finally: 373
No try/catch/finally: 329

   try/catch/finally: 373
No try/catch/finally: 330

   try/catch/finally: 373
No try/catch/finally: 352

   try/catch/finally: 374
No try/catch/finally: 331

   try/catch/finally: 380
No try/catch/finally: 329

   try/catch/finally: 374
No try/catch/finally: 334

在看到try / catch和没有try / catch的所有统计数据后,好奇心迫使我往后看,看看这两种情况产生了什么。 代码如下:

C#:

private static void TestWithoutTryCatch(){
    Console.WriteLine("SIN(1) = {0} - No Try/Catch", Math.Sin(1)); 
}

MSIL:

.method private hidebysig static void  TestWithoutTryCatch() cil managed
{
  // Code size       32 (0x20)
  .maxstack  8
  IL_0000:  nop
  IL_0001:  ldstr      "SIN(1) = {0} - No Try/Catch"
  IL_0006:  ldc.r8     1.
  IL_000f:  call       float64 [mscorlib]System.Math::Sin(float64)
  IL_0014:  box        [mscorlib]System.Double
  IL_0019:  call       void [mscorlib]System.Console::WriteLine(string,
                                                                object)
  IL_001e:  nop
  IL_001f:  ret
} // end of method Program::TestWithoutTryCatch

C#:

private static void TestWithTryCatch(){
    try{
        Console.WriteLine("SIN(1) = {0}", Math.Sin(1)); 
    }
    catch (Exception ex){
        Console.WriteLine(ex);
    }
}

MSIL:

.method private hidebysig static void  TestWithTryCatch() cil managed
{
  // Code size       49 (0x31)
  .maxstack  2
  .locals init ([0] class [mscorlib]System.Exception ex)
  IL_0000:  nop
  .try
  {
    IL_0001:  nop
    IL_0002:  ldstr      "SIN(1) = {0}"
    IL_0007:  ldc.r8     1.
    IL_0010:  call       float64 [mscorlib]System.Math::Sin(float64)
    IL_0015:  box        [mscorlib]System.Double
    IL_001a:  call       void [mscorlib]System.Console::WriteLine(string,
                                                                  object)
    IL_001f:  nop
    IL_0020:  nop
    IL_0021:  leave.s    IL_002f //JUMP IF NO EXCEPTION
  }  // end .try
  catch [mscorlib]System.Exception 
  {
    IL_0023:  stloc.0
    IL_0024:  nop
    IL_0025:  ldloc.0
    IL_0026:  call       void [mscorlib]System.Console::WriteLine(object)
    IL_002b:  nop
    IL_002c:  nop
    IL_002d:  leave.s    IL_002f
  }  // end handler
  IL_002f:  nop
  IL_0030:  ret
} // end of method Program::TestWithTryCatch

我不是IL方面的专家,但是我们可以看到在第四行.locals init ([0] class [mscorlib]System.Exception ex)上创建了一个局部异常对象,事情跟没有try /赶上17 IL_0021: leave.s IL_002f线IL_0021: leave.s IL_002f 。 如果发生异常,则控制跳转到IL_0025: ldloc.0IL_0025: ldloc.0否则我们跳转到标签IL_002d: leave.s IL_002f并返回函数。

我可以安全地假设,如果没有发生异常,那么创建局部变量仅用于保存异常对象和跳转指令会产生开销。


不可以。如果try / finally块排除的微小优化实际上会对程序产生可衡量的影响,那么您可能不应该首先使用.NET。

链接地址: http://www.djcxy.com/p/17963.html

上一篇: Do try/catch blocks hurt performance when exceptions are not thrown?

下一篇: How to convert a Map to List in Java?