【问题标题】:what will empty catch and throw block do?空的 catch 和 throw 块会做什么?
【发布时间】:2013-11-24 01:32:09
【问题描述】:

我知道下面的catch and throw块是多余的,我很好奇它能造成什么样的伤害?

编译器可以在发布模式下优化它吗?或者它无论如何都会捕获异常并重新抛出它?如果是后一种情况,会造成什么样的性能损失?

try
{
  //...
}
catch {
  throw;
}

【问题讨论】:

  • 我会编译一个示例,然后使用ILSpy 或其他.NET 反汇编程序查看反汇编代码。
  • 我不同意这是重复的。 OP 表示他已经知道代码是多余的并且可以删除。相反,他想知道保留代码的实际影响是什么。

标签: .net performance exception


【解决方案1】:

优化

即使在发布版本中,编译器也不会对此进行优化。

参加以下测试申请:

public class Program {
    public static void Main(string[] args) {
        try {
            CallsThrow();
        }
        catch(Exception ex) {
            Console.WriteLine("Main() caught exception: " + ex.Message);
        }
        Console.Read();
    }

    private static void CallsThrow() {
        try {
            Throw();
        }
        catch {
            throw;
        }
    }

    private static void Throw() {
        throw new Exception("Here's my exception.");
    }
}

使用ILSpy,我们可以查看IL 级别的输出二进制文件。我们看到CallsThrow 中的try/catch 在我们的Release 二进制文件中仍然存在:

.method private hidebysig static 
    void CallsThrow () cil managed 
{
    // Method begins at RVA 0x2094
    // Code size 11 (0xb)
    .maxstack 1

    .try
    {
        IL_0000: call void JunkCSharpConsole.Program::Throw()
        IL_0005: leave.s IL_000a
    } // end .try
    catch [mscorlib]System.Object
    {
        IL_0007: pop
        IL_0008: rethrow
    } // end handler

    IL_000a: ret
} // end of method Program::CallsThrow

基准测试

代码:

public class Program
{
    public static void Main(string[] args) {
        const int N = 100000000;
#if DEBUG
        const string mode = "Debug";
#else
        const string mode = "Release";
#endif

        Console.WriteLine("Testing {0} iterations in {1} mode:", N, mode);

        // Attempt to JIT / cache
        CallsThrowWithTryCatch(false);
        CallsThrowWithoutTryCatch(false);

        // Test with try/catch+throw
        var s1 = Stopwatch.StartNew();
        for (int i = 0; i < N; i++ )
            CallsThrowWithTryCatch(false);
        s1.Stop();
        Console.WriteLine("  With try/catch: {0} ms", s1.ElapsedMilliseconds);

        // Test without try/catch+throw
        var s2 = Stopwatch.StartNew();
        for (int i = 0; i < N; i++)
            CallsThrowWithoutTryCatch(false);
        s2.Stop();
        Console.WriteLine("  Without try/catch: {0} ms", s2.ElapsedMilliseconds);

        var pct = (s1.ElapsedMilliseconds - s2.ElapsedMilliseconds) / (double)s1.ElapsedMilliseconds * 100.0;
        Console.WriteLine("No try/catch faster by {0:.02}%", pct);

        // Just show that it works
        try {
            CallsThrowWithTryCatch(true);
        }
        catch (Exception ex) {
            Console.WriteLine("Main() caught exception: " + ex.Message);
        }

        // Wait to exit
        Console.WriteLine("Press ENTER to exit.");
        Console.Read();
    }

    private static void CallsThrowWithTryCatch(bool doThrow) {
        try {
            Throw(doThrow);
        }
        catch {
            throw;
        }
    }

    private static void CallsThrowWithoutTryCatch(bool doThrow) {
        Throw(doThrow);
    }

    private static void Throw(bool doThrow) {
        if (doThrow)
            throw new Exception("Here's my exception.");
    }
}

结果:

Testing 100000000 iterations in Debug mode:
  With try/catch: 1492 ms
  Without try/catch: 1474 ms
No try/catch faster by 1.22%
Main() caught exception: Here's my exception.
Press ENTER to exit.

Testing 100000000 iterations in Release mode:
  With try/catch: 598 ms
  Without try/catch: 458 ms
No try/catch faster by 23.42%
Main() caught exception: Here's my exception.
Press ENTER to exit.

我们可以看到,是的,即使是空的try/catch,也会有一个性能损失。在 Debug 版本中它并不那么重要,但 Release 版本通过删除 try/catch 显示了 23.42% 的显着改进。

【讨论】:

  • 再投掷一次的开销将是最小的,第二次转储 IL 是留给读者的一项微不足道的练习,那么回答这样的问题的价值在哪里?
  • 开销显然不是最小的。你看过数字吗?此外,对于更有经验的开发人员来说,这可能是微不足道的,但我敢肯定,有很大一部分 .NET 开发人员不知道您可以在 IL 级别查看生成的二进制文件。
  • 微软说只处理那些需要处理的异常,因为需要执行操作或可能发生修复,否则让下一级异常处理程序处理它,在这种情况下这将是最后一次机会异常处理程序,从功能上讲,代码与没有 try catch 块的代码相同。我推荐它吗?不,性能影响是灾难性的吗? 更糟糕的是此时抛出会阻碍调试。
  • 我完全理解包含和排除相关处理程序的行为含义。我相信OP也是如此。他询问了包含处理程序的低级影响,我尽力回答了他的具体问题。我认为您的担忧在这里基本上不会被听到。
  • 实际上上面的空catch, throw代码是从我们的架构师编写的项目中复制的,我知道它从第一印象就很臭,你的回答帮助我理解了为什么它闻起来。我应该告诉他还是不告诉他,这是另一个问题:)
猜你喜欢
  • 1970-01-01
  • 2013-01-18
  • 2011-04-12
  • 2014-03-18
  • 2012-06-04
  • 1970-01-01
  • 1970-01-01
  • 2015-03-05
  • 2010-12-14
相关资源
最近更新 更多